【Thread】线程的死锁与锁(四)
2021/11/6 23:14:34
本文主要是介绍【Thread】线程的死锁与锁(四),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1. 死锁
多个线程各自占用一些共享资源,并且互相等待其它线程占有的资源才能运行,而导致两个或多个线程都在等待对方释放资源,都停止执行的情形。
某一个同步代码块同时拥有两个以上对象的锁时,就有可能发生死锁的问题。
案例:女生化妆。化妆品有:镜子、口红。灰姑娘先选择口红,再选择镜子;白雪公主先选择镜子,再选择口红
// 口红 class Lipstick {} // 镜子 class Mirror {} class Makeup extends Thread { private static Lipstick lipstick = new Lipstick(); private static Mirror mirror = new Mirror(); private int choice; private String girlName; public Makeup(int choice, String girlName) { this.choice = choice; this.girlName = girlName; } @Override public void run() { try { makeup(); } catch (Exception e) { e.printStackTrace(); } } // 化妆 private void makeup() throws Exception{ if (0 == choice) { synchronized (lipstick) { System.out.println(this.girlName + "拿到了口红的锁"); Thread.sleep(1000); synchronized (mirror) { System.out.println(this.girlName + "拿到了镜子的锁"); } } } else { synchronized (mirror) { System.out.println(this.girlName + "拿到了镜子的锁"); Thread.sleep(2000); synchronized (lipstick) { System.out.println(this.girlName + "拿到了口红的锁"); } } } } }
测试:
// 死锁 多个线程互相持有对方需要的资源,然后形成僵持 public class DeadLock { public static void main(String[] args) { Makeup g1 = new Makeup(0, "灰姑凉"); Makeup g2 = new Makeup(1, "白雪公主"); g1.start(); g2.start(); } }
运行后:
程序一直处于死锁状态。
那么,如何解除这种状态呢?
class Makeup extends Thread { ... // 化妆 private void makeup() throws Exception{ if (0 == choice) { synchronized (lipstick) { System.out.println(this.girlName + "拿到了口红的锁"); Thread.sleep(1000); } synchronized (mirror) { System.out.println(this.girlName + "拿到了镜子的锁"); } } else { synchronized (mirror) { System.out.println(this.girlName + "拿到了镜子的锁"); Thread.sleep(2000); } synchronized (lipstick) { System.out.println(this.girlName + "拿到了口红的锁"); } } } }
运行结果如下:
2.锁 Lock
从 JDK 1.5 开始,Java 提供了更强大的线程同步机制:通过显示定义同步锁对象来实现同步。同步锁使用 Lock
对象充当。
java.util.concurrent.locks.Lock
接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对 Lock 对象加锁,线程开始访问共享资源之前应先获得 Lock 对象。
ReentrantLock
类实现了 Lock
接口,它拥有与 synchronized
相同的并发性和内存语义。在实现线程安全的控制中,比较常用的是 ReentrantLock
,可以显示地加锁、释放锁。
Lock
与 synchronized
的比较:
- Lock 显示锁,手动加锁、解锁;用 Lock,JVM 将花费较少的时间来调度线程,性能更好
- synchronized 隐式锁,出了作用域自动释放
案例:使用 Lock 实现线程安全地买票
class TestLock2 implements Runnable { private int ticketNums = 10; // 可重入锁 private final ReentrantLock lock = new ReentrantLock(); @Override public void run() { while (true) { lock.lock(); try { if (ticketNums <= 0) { break; } try { Thread.sleep(1000); System.out.println(ticketNums--); } catch (InterruptedException e) { e.printStackTrace(); } } finally { lock.unlock(); } } } }
测试:
public class TestLock { public static void main(String[] args) { TestLock2 testLock2 = new TestLock2(); new Thread(testLock2).start(); new Thread(testLock2).start(); new Thread(testLock2).start(); } }
这篇关于【Thread】线程的死锁与锁(四)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-30java最新版本是什么,有什么特性?-icode9专业技术文章分享
- 2024-11-30[开源]27.8K star!这款 Postman 替代工具太火了!
- 2024-11-30Gzip 压缩入门教程:轻松掌握文件压缩技巧
- 2024-11-29开源工具的魅力:让文档管理更“聪明”
- 2024-11-29Release-it开发入门教程
- 2024-11-29Rollup 插件入门教程:轻松掌握模块打包
- 2024-11-29从零到一,产品经理如何玩转项目管理和团队协作
- 2024-11-29如何通过精益生产管理工具帮助项目团队实现精准进度控制?
- 2024-11-29低代码应用开发课程:新手入门与基础教程
- 2024-11-29入门指南:全栈低代码开发课程