Java并发编程 - 锁Lock 取款机场景实例(转)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java并发编程 - 锁Lock 取款机场景实例(转),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含10320字,纯文字阅读大概需要15分钟。
内容图文
![Java并发编程 - 锁Lock 取款机场景实例(转)](/upload/InfoBanner/zyjiaocheng/755/218cb85010da4177adb5bf2cef45f6d9.jpg)
Lock是一个接口,ReentrantLock是它的实现类,下面通过“取款机案例”来剖析它的4个常用方法。
1.爸爸妈妈同时在ATM上登录取款(不加任何锁)
public class Bank { private static double money = 10000; public void login(Thread currentUserThread) { System.out.println(Thread.currentThread().getName() + " 登录进入银行" + " 当前银行余额 : " + money); } public void logout() { System.out.println(Thread.currentThread().getName() + " 退出银行"); } public double withdraw(double withdrawMoney) { if (this.money < withdrawMoney) { System.out.println(Thread.currentThread().getName() + " 当前银行余额 : " + this.money + " 余额不够"); return 0; } this.money -= withdrawMoney; System.out.println(Thread.currentThread().getName() + " 取款 : " + withdrawMoney + " 当前银行余额 : " + this.money); return withdrawMoney; } }
public class TestLock { public static void main(String[] args) { final Bank bank = new Bank(); //启动爸爸线程 Thread fatherThread = new Thread("爸爸") { public void run() { try { //爸爸登录 bank.login(Thread.currentThread()); //过2秒取10000 Thread.sleep(2000); bank.withdraw(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }; fatherThread.start(); // 启动妈妈线程 Thread motherThread = new Thread("妈妈") { public void run() { try { //妈妈登录 bank.login(Thread.currentThread()); //过5秒取 10000 Thread.sleep(5000); bank.withdraw(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }; motherThread.start(); } }
结果:
妈妈 登录进入银行 当前银行余额 : 10000.0 爸爸 登录进入银行 当前银行余额 : 10000.0 爸爸 取款 : 10000.0 当前银行余额 : 0.0 妈妈 当前银行余额 : 0.0 余额不够
妈妈登录显示银行余额为10000,但是当她取钱时却显示“余额不足”,产生了数据不一致。
2.同一时刻,爸爸或妈妈线程只能有一个能够登录银行取款(获取lock()),另外一个线程需要等待, 直到unlock()释放锁
public class Bank { private static double money = 10000; private Lock lock = new ReentrantLock(); public void login(Thread currentUserThread) { lock.lock();//登录加锁 System.out.println(Thread.currentThread().getName() + " 登录进入银行" + " 当前银行余额 : " + money); } public void logout() { lock.unlock();//退出释放锁 System.out.println(Thread.currentThread().getName() + " 退出银行"); } public double withdraw(double withdrawMoney) { if (this.money < withdrawMoney) { System.out.println(Thread.currentThread().getName() + " 当前银行余额 : " + this.money + " 余额不够"); return 0; } this.money -= withdrawMoney; System.out.println(Thread.currentThread().getName() + " 取款 : " + withdrawMoney + " 当前银行余额 : " + this.money); return withdrawMoney; } }
public class TestLock { public static void main(String[] args) { final Bank bank = new Bank(); //启动爸爸线程 Thread fatherThread = new Thread("爸爸") { public void run() { try { //爸爸登录 bank.login(Thread.currentThread()); //过2秒取10000 Thread.sleep(2000); bank.withdraw(10000); //爸爸退出 bank.logout(); } catch (InterruptedException e) { e.printStackTrace(); } } }; fatherThread.start(); // 启动妈妈线程 Thread motherThread = new Thread("妈妈") { public void run() { try { //妈妈登录 bank.login(Thread.currentThread()); //过5秒取 10000 Thread.sleep(5000); bank.withdraw(10000); //妈妈退出 bank.logout(); } catch (InterruptedException e) { e.printStackTrace(); } } }; motherThread.start(); } }
结果:
爸爸 登录进入银行 当前银行余额 : 10000.0 爸爸 取款 : 10000.0 当前银行余额 : 0.0 爸爸 退出银行 妈妈 登录进入银行 当前银行余额 : 0.0 妈妈 当前银行余额 : 0.0 余额不够 妈妈 退出银行
lock() 和unlock()成对出现,在login(Thread currentUserThread) 登录方法中调用 lock() ,在 logout()退出方法中调用了unlock()。
也就是说,Lock类的锁机制允许在不同的方法中加锁和解锁,而synchronized关键字只能在同一个方法中加锁和解锁。
3. 通过tryLock()判断是否可以获得锁, 能获得锁返回true,否则返回false
public class Bank { private static double money = 10000; private Lock lock = new ReentrantLock(); public void login(Thread currentUserThread) { //判断是否已经有线程登录 if (!lock.tryLock()) { System.out.println(Thread.currentThread().getName() + " 有人已经登录进入银行 请稍等"); } else { System.out.println(Thread.currentThread().getName() + " 登录进入银行" + " 当前银行余额: " + money); } } public void logout() { lock.unlock();//退出释放锁 System.out.println(Thread.currentThread().getName() + " 退出银行"); } public double withdraw(double withdrawMoney) { if (this.money < withdrawMoney) { System.out.println(Thread.currentThread().getName() + " 当前银行余额: " + this.money + " 余额不够"); return 0; } this.money -= withdrawMoney; System.out.println(Thread.currentThread().getName() + " 取款: " + withdrawMoney + " 当前银行余额: " + this.money); return withdrawMoney; } }
public class TestLock { public static void main(String[] args) { final Bank bank = new Bank(); //启动爸爸线程 Thread fatherThread = new Thread("爸爸") { public void run() { try { //爸爸登录 bank.login(Thread.currentThread()); //过2秒取10000 Thread.sleep(2000); bank.withdraw(10000); //爸爸退出 bank.logout(); } catch (InterruptedException e) { e.printStackTrace(); } } }; fatherThread.start(); // 启动妈妈线程 Thread motherThread = new Thread("妈妈") { public void run() { //妈妈登录 bank.login(Thread.currentThread()); } }; motherThread.start(); } }
结果:
妈妈 有人已经登录进入银行 请稍等 爸爸 登录进入银行 当前银行余额: 10000.0 爸爸 取款: 10000.0 当前银行余额: 0.0 爸爸 退出银行
4. 通过tryLock(long time,TimeUnit timeUnit)设置一段时间后重新进入
public class Bank { private static double money = 10000; private Lock lock = new ReentrantLock(); public void login(Thread currentUserThread) { //如果登录不成功,10秒后再重新尝试获得锁 try { if (!lock.tryLock(10, TimeUnit.SECONDS)) { System.out.println(Thread.currentThread().getName() + " 有人已经登录进入银行,请稍等"); } else { System.out.println(Thread.currentThread().getName() + " 登录进入银行" + " 当前银行余额: " + money); } } catch (InterruptedException e) { e.printStackTrace(); } } public void logout() { lock.unlock();//退出释放锁 System.out.println(Thread.currentThread().getName() + " 退出银行"); } public double withdraw(double withdrawMoney) { if (this.money < withdrawMoney) { System.out.println(Thread.currentThread().getName() + " 当前银行余额: " + this.money + " 余额不够"); return 0; } this.money -= withdrawMoney; System.out.println(Thread.currentThread().getName() + " 取款: " + withdrawMoney + " 当前银行余额: " + this.money); return withdrawMoney; } }
public class TestLock { public static void main(String[] args) { final Bank bank = new Bank(); //启动爸爸线程 Thread fatherThread = new Thread("爸爸") { public void run() { try { //爸爸登录 bank.login(Thread.currentThread()); //过2秒取10000 Thread.sleep(2000); bank.withdraw(10000); //爸爸退出 bank.logout(); } catch (InterruptedException e) { e.printStackTrace(); } } }; fatherThread.start(); // 启动妈妈线程 Thread motherThread = new Thread("妈妈") { public void run() { //妈妈登录 bank.login(Thread.currentThread()); } }; motherThread.start(); } }
结果妈妈10秒后重新尝试得到锁登录进入了银行 :
爸爸 登录进入银行 当前银行余额: 10000.0 爸爸 取款: 10000.0 当前银行余额: 0.0 爸爸 退出银行 妈妈 登录进入银行 当前银行余额: 0.0
5.如果爸爸线程调用 lock() 获得锁以后,没有unlock()释放锁,妈妈线程将会一直等待产生死锁,即使调用 interrupt()中断也没有作用。
public class Bank { private static double money = 10000; private Lock lock = new ReentrantLock(); public void login(Thread currentUserThread) { lock.lock(); System.out.println(Thread.currentThread().getName() + " 登录进入银行" + " 当前银行余额 : " + money); } public void logout() { lock.unlock();//退出释放锁 System.out.println(Thread.currentThread().getName() + " 退出银行"); } public double withdraw(double withdrawMoney) { if (this.money < withdrawMoney) { System.out.println(Thread.currentThread().getName() + " 当前银行余额: " + this.money + " 余额不够"); return 0; } this.money -= withdrawMoney; System.out.println(Thread.currentThread().getName() + " 取款: " + withdrawMoney + " 当前银行余额: " + this.money); return withdrawMoney; } }
public class TestLock { public static void main(String[] args) { final Bank bank = new Bank(); //启动爸爸线程 Thread fatherThread = new Thread("爸爸") { public void run() { try { //爸爸登录 bank.login(Thread.currentThread()); //过2秒取10000 Thread.sleep(2000); bank.withdraw(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }; fatherThread.start(); // 启动妈妈线程 Thread motherThread = new Thread("妈妈") { public void run() { try { Thread.sleep(1000); bank.login(Thread.currentThread()); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName()+" 登录超时被中断"); } } }; motherThread.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } motherThread.interrupt(); } }
结果:
妈妈线程一直等待爸爸线程释放锁,结果造成死锁。妈妈线程调用motherThread.interrupt(); 中断也不起做用。
6. 在登录获得锁时,调用lockInterruptibly(),允许中断等待的线程,使motherThread.interrupt()可用。
public class Bank { private static double money = 10000; private Lock lock = new ReentrantLock(); public void login(Thread currentUserThread) throws InterruptedException { lock.lockInterruptibly();//运行等待线程被中断 System.out.println(Thread.currentThread().getName() + " 登录进入银行" + " 当前银行余额 : " + money); } public void logout() { lock.unlock();//退出释放锁 System.out.println(Thread.currentThread().getName() + " 退出银行"); } public double withdraw(double withdrawMoney) { if (this.money < withdrawMoney) { System.out.println(Thread.currentThread().getName() + " 当前银行余额: " + this.money + " 余额不够"); return 0; } this.money -= withdrawMoney; System.out.println(Thread.currentThread().getName() + " 取款: " + withdrawMoney + " 当前银行余额: " + this.money); return withdrawMoney; } }
public class TestLock { public static void main(String[] args) { final Bank bank = new Bank(); //启动爸爸线程 Thread fatherThread = new Thread("爸爸") { public void run() { try { //爸爸登录 bank.login(Thread.currentThread()); //过2秒取10000 Thread.sleep(2000); bank.withdraw(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }; fatherThread.start(); // 启动 妈妈 线程 Thread motherThread = new Thread("妈妈") { public void run() { try { Thread.sleep(1000); bank.login(Thread.currentThread()); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName()+" 登录超时被中断"); } } }; motherThread.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } motherThread.interrupt(); } }
结果:
爸爸 登录进入银行 当前银行余额 : 10000.0 妈妈 登录超时被中断 爸爸 取款: 10000.0 当前银行余额: 0.0
转自:http://www.verejava.com/?id=17236703718463
内容总结
以上是互联网集市为您收集整理的Java并发编程 - 锁Lock 取款机场景实例(转)全部内容,希望文章能够帮你解决Java并发编程 - 锁Lock 取款机场景实例(转)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。