Lock是java5提供的一個強大的線程同步機制--通過顯示定義同步鎖對象來實現同步。Lock可以顯示的加鎖、解鎖。每次只能有一個線程對lock對象加鎖。
Lock有ReadLock、WriteLock、ReentrantLock(可重入鎖)
常用的就是ReentrantLock。代碼如下:
代碼邏輯:Account賬戶類,實現取錢的同步方法、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
{
//賬戶余額大於取錢數目
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;
/**
* 調用account取錢
*
*/
public class DrawThread extends Thread
{
//模擬用戶賬戶
private Account account;
//當前取錢線程所希望取的錢數
private double drawAmount;
public DrawThread(String name , Account account ,
double drawAmount)
{
super(name);
this.account = account;
this.drawAmount = drawAmount;
}
//當多條線程修改同一個共享數據時,將涉及到數據安全問題。
public void run()
{
account.draw(drawAmount);
}
}
TestDraw:
package lock.reentrantlock2;
/**
*/
public class TestDraw
{
public static void main(String[] args)
{
//創建一個賬戶
Account acct = new Account("1234567" , 1000);
//模擬兩個線程對同一個賬戶取錢
new DrawThread("甲" , acct , 800).start();
new DrawThread("乙" , acct , 800).start();
}
}
運行結果:
甲取錢成功!吐出鈔票:800.0
余額為: 200.0
乙取錢失敗!余額不足!
使用Lock同步與同步方法很相似,都是“加鎖--修改公共變量--釋放鎖”的模式,代碼很容易看懂。兩個線程對應一個Account對象,保證了兩個線程對應一個lock對象,保證了同一時刻只有一個線程進入臨界區。Lock還包含太容易Lock(),以及試圖獲取可中斷鎖的lockInterruptibly(),獲取超時失效鎖的tryLock(long,TimeUnit)等方法。
ReentrantLock鎖具有可重入性可以對已被加鎖的ReentrantLock鎖再次加鎖,線程每次調用lock()加鎖後,必須顯示的調用unlock來釋放鎖,有幾個lock就對應幾個unlock。還有把unlock放在finally代碼塊中,Lock在發生異常時也是不釋放鎖的,所以在finally中釋放更安全。
只是對Lock簡單說明了下,為下一篇線程通信打基礎。