Java線程同步Lock同步鎖代碼示例
java線程同步原理
java會為每個object對象分配一個monitor,當某個對象的同步方法(synchronizedmethods)被多個線程調(diào)用時,該對象的monitor將負責處理這些訪問的并發(fā)獨占要求。
當一個線程調(diào)用一個對象的同步方法時,JVM會檢查該對象的monitor。如果monitor沒有被占用,那么這個線程就得到了monitor的占有權(quán),可以繼續(xù)執(zhí)行該對象的同步方法;如果monitor被其他線程所占用,那么該線程將被掛起,直到monitor被釋放。
當線程退出同步方法調(diào)用時,該線程會釋放monitor,這將允許其他等待的線程獲得monitor以使對同步方法的調(diào)用執(zhí)行下去。
注意:Java對象的monitor機制和傳統(tǒng)的臨界檢查代碼區(qū)技術(shù)不一樣。java的一個同步方法并不意味著同時只有一個線程獨占執(zhí)行,但臨界檢查代碼區(qū)技術(shù)確實會保證同步方法在一個時刻只被一個線程獨占執(zhí)行。Java的monitor機制的準確含義是:任何時刻,對一個指定object對象的某同步方法只能由一個線程來調(diào)用。
java對象的monitor是跟隨object實例來使用的,而不是跟隨程序代碼。兩個線程可以同時執(zhí)行相同的同步方法,比如:一個類的同步方法是xMethod(),有a,b兩個對象實例,一個線程執(zhí)行a.xMethod(),另一個線程執(zhí)行b.xMethod().互不沖突。
Lock-同步鎖
Lock是java5提供的一個強大的線程同步機制--通過顯示定義同步鎖對象來實現(xiàn)同步。Lock可以顯示的加鎖、解鎖。每次只能有一個線程對lock對象加鎖。
Lock有ReadLock、WriteLock、ReentrantLock(可重入鎖)
常用的就是ReentrantLock。代碼如下:
代碼邏輯:Account賬戶類,實現(xiàn)取錢的同步方法、DrawThread取錢的線程
Account:
package lock.reentrantlock2;
import java.util.concurrent.locks.*;
/**
*賬戶類,需保持同步
*/
public class Account
{
//定義鎖對象
private final ReentrantLock lock = new ReentrantLock();
private String accountNo;
private double balance;
public Account(){}
public Account(String accountNo , double balance)
{
this.accountNo = accountNo;
this.balance = balance;
}
public void setAccountNo(String accountNo)
{
this.accountNo = accountNo;
}
public String getAccountNo()
{
return this.accountNo;
}
public double getBalance()
{
return this.balance;
}
public void draw(double drawAmount)
{
lock.lock();
try
{
//賬戶余額大于取錢數(shù)目
if (balance >= drawAmount)
{
//吐出鈔票
System.out.println(Thread.currentThread().getName() +
"取錢成功!吐出鈔票:" + drawAmount);
try
{
Thread.sleep(1);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
//修改余額
balance -= drawAmount;
System.out.println("\t余額為: " + balance);
}
else
{
System.out.println(Thread.currentThread().getName() +
"取錢失??!余額不足!");
}
}
finally
{
lock.unlock();
}
}
public int hashCode()
{
return accountNo.hashCode();
}
public boolean equals(Object obj)
{
if (obj != null && obj.getClass() == Account.class)
{
Account target = (Account)obj;
return target.getAccountNo().equals(accountNo);
}
return false;
}
}
DrawThread:
package lock.reentrantlock2;
/**
* 調(diào)用account取錢
*
*/
public class DrawThread extends Thread
{
//模擬用戶賬戶
private Account account;
//當前取錢線程所希望取的錢數(shù)
private double drawAmount;
public DrawThread(String name , Account account ,
double drawAmount)
{
super(name);
this.account = account;
this.drawAmount = drawAmount;
}
//當多條線程修改同一個共享數(shù)據(jù)時,將涉及到數(shù)據(jù)安全問題。
public void run()
{
account.draw(drawAmount);
}
}
TestDraw:
package lock.reentrantlock2;
/**
*/
public class TestDraw
{
public static void main(String[] args)
{
//創(chuàng)建一個賬戶
Account acct = new Account("1234567" , 1000);
//模擬兩個線程對同一個賬戶取錢
new DrawThread("甲" , acct , 800).start();
new DrawThread("乙" , acct , 800).start();
}
}
運行結(jié)果:
甲取錢成功!吐出鈔票:800.0
余額為:200.0
乙取錢失??!余額不足!
使用Lock同步與同步方法很相似,都是“加鎖--修改公共變量--釋放鎖”的模式,代碼很容易看懂。兩個線程對應(yīng)一個Account對象,保證了兩個線程對應(yīng)一個lock對象,保證了同一時刻只有一個線程進入臨界區(qū)。Lock還包含太容易Lock(),以及試圖獲取可中斷鎖的lockInterruptibly(),獲取超時失效鎖的tryLock(long,TimeUnit)等方法。
ReentrantLock鎖具有可重入性可以對已被加鎖的ReentrantLock鎖再次加鎖,線程每次調(diào)用lock()加鎖后,必須顯示的調(diào)用unlock來釋放鎖,有幾個lock就對應(yīng)幾個unlock。還有把unlock放在finally代碼塊中,Lock在發(fā)生異常時也是不釋放鎖的,所以在finally中釋放更安全。
總結(jié)
以上就是本文關(guān)于Java線程同步Lock同步鎖代碼示例的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:
Java編程之多線程死鎖與線程間通信簡單實現(xiàn)代碼
有什么問題可以隨時留言,小編會及時回復大家的。感謝朋友們對本站的支持!
相關(guān)文章
Java中Stream流中map和forEach的區(qū)別詳解
本文主要介紹了Java中Stream流中map和forEach的區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-04-04
SpringSecurity配置HTTPS的實現(xiàn)
本文介紹了SpringBoot項目中配置HTTPS并集成SpringSecurity,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2025-01-01
Java基礎(chǔ)教程之對象的方法與數(shù)據(jù)成員
這篇文章主要介紹了Java基礎(chǔ)教程之對象的方法與數(shù)據(jù)成員,本文講解對象的方法與數(shù)據(jù)成員相關(guān)知識,因為java是面向?qū)ο笳Z言,本文的知識都是經(jīng)常要用到的,需要的朋友可以參考下2014-08-08
手把手教你idea中創(chuàng)建一個javaweb(webapp)項目詳細圖文教程
這篇文章主要介紹了如何使用IntelliJ?IDEA創(chuàng)建一個Maven項目,并配置Tomcat服務(wù)器進行運行,過程包括創(chuàng)建項目、配置運行環(huán)境、部署項目以及測試運行,需要的朋友可以參考下2025-01-01
springboot如何獲取application.yml里值的方法
這篇文章主要介紹了springboot如何獲取application.yml里的值,文章圍繞主題相關(guān)自資料展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-04-04
Java基于外觀模式實現(xiàn)美食天下食譜功能實例詳解
這篇文章主要介紹了Java基于外觀模式實現(xiàn)美食天下食譜功能,較為詳細的講述了外觀模式的概念、原理并結(jié)合實例形似詳細分析了Java基于外觀模式實現(xiàn)美食天下食譜功能的具體操作步驟與相關(guān)注意事項,需要的朋友可以參考下2018-05-05
springboot?maven?plugin報紅的解決辦法
本文主要介紹了springboot?maven?plugin報紅的解決辦法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-07-07

