你的位置:首页 > Java教程

[Java教程]Lock同步锁


Lock-同步锁

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简单说明了下,为下一篇线程通信打基础。