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