线程死锁的原因 ゝ一世哀愁。 2024-03-23 07:31 42阅读 0赞 ## 造成线程死锁的原因以及解决方案 ## ### 造成死锁的原因 ### #### 一个线程一把锁 #### 这种情况 可重入锁没事,不可重入锁会造成死锁, Java 中 synchronized是可重入锁, 因此没有问题 *(所谓重入锁,指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的。)* public class Test { static Object locker1 = new Object(); public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { test(); }); t1.start(); t1.join(); System.out.println("没有造成死锁!"); } public static void test() { // 多个锁情况 synchronized (locker1) { synchronized (locker1){ System.out.println("执行测试方法"); } } } } 运行结果如下: 使用synchronized 并没有造成死锁情况 但是如果不是synchronized的话,是其他的不可重入锁 就会造成死锁情况 ![在这里插入图片描述][590d1927fcde4d28b408229388e7022f.png] #### 两个线程两把锁 #### 两个线程两把锁, 此时当两个线程获取两把锁对象的时候顺序并不一样,此时很容易造成死锁 public class Test { static Object locker1 = new Object(); static Object locker2 = new Object(); public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { try { test(); } catch (InterruptedException e) { e.printStackTrace(); } }); t1.start(); Thread t2 = new Thread(() -> { test2(); }); t2.start(); } public static void test() throws InterruptedException { // 多个锁情况 synchronized (locker1) { System.out.println("t1 进入第一把锁!"); // 为了让线程 2拿到 锁2 Thread.sleep(1000); synchronized (locker2){ System.out.println("t1 进入第二把锁!"); } } } public static void test2() { synchronized (locker2) { System.out.println("t2 进入第一把锁! "); synchronized (locker1) { System.out.println("t2 进入第二把锁! "); } } } } 运行结果如下: 线程1和线程2都进入到了第一把锁里面 但是谁都没有释放锁 ,因此导致了线程的死锁情况 其实解决方案很简单, 只需要指定加锁顺序,(外层锁1, 内层锁2) 这样即使 线程1 拿到了外层锁1 , 此时线程 2 拿不到 锁1 就进不去, 就会阻塞等待,直到线程1执行完程序, 释放锁1 和锁2 此时线程2 才能拿到锁1 执行下去. public class Test { static Object locker1 = new Object(); static Object locker2 = new Object(); public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { try { test(); } catch (InterruptedException e) { e.printStackTrace(); } }); t1.start(); Thread t2 = new Thread(() -> { test2(); }); t2.start(); t1.join(); t2.join(); System.out.println("没有造成死锁!"); } // 指定两个方法都是外层锁1加锁, 内层锁2 加锁. public static void test() throws InterruptedException { // 多个锁情况 synchronized (locker1) { System.out.println("t1 进入第一把锁!"); Thread.sleep(1000); synchronized (locker2){ System.out.println("t1 进入第二把锁!"); } } } public static void test2() { synchronized (locker1) { System.out.println("t2 进入第一把锁! "); synchronized (locker2) { System.out.println("t2 进入第二把锁! "); } } } } 结果如下: ![在这里插入图片描述][d9e8322bf2d341918f4c6cd384e78dff.png] #### n个线程m把锁 #### 举个例子, 就餐问题,如果有五个人(5个线程) 此时筷子也只有五根(5把锁) 但是每个人都需要拿两根筷子才可以就餐,(一个线程调用某个方法需要抢两把锁) 此时如果每个人都拿到了面前的一根筷子,那么谁都吃不了饭, 也就是说, 线程进入了死锁状态! ![在这里插入图片描述][594d5a1ab5f44a4a90e582a44192035d.png] 因此总结得出 ,死锁的四个必要条件: 1. 因为线程是抢占式执行,并且锁是互斥使用, 因此一个线程拿到一把锁的时候, 另一个线程就不能使用 (锁的基本特点) 2. 不可占用: 一个线程拿到了锁,只能够自己执行完方法 ,释放锁资源, 而不能被其他线程强行占有 3. 请求和保持, 在一个方法内,如果线程拿到一把锁之后,还会想着抢第二把锁,(代码向下执行的特点) 因此,第一把锁在没有执行完该方法,或者在synchronized加锁范围内 是不会释放锁的,并且不断请求获取第二把锁, 从而形成死锁 4. 循环等待, 相当于加锁顺序不同, “家钥匙锁在车里了, 车钥匙放家里了”. ### 死锁的解决方案 ### 因此针对与形成死锁的四个必要条件,总结出解决方案: **针对锁进行编号, 如果需要同时获取多把锁的情况,约定加锁顺序, 务必是先对小的编号加锁,后对大的编号加锁** 例如 N个线程 M把锁情况: 约定好先获取编号小的筷子, 在获取编号大的筷子 ,并且五个人每个人需要两根筷子,满足只允许4个人同时拿起筷子,那么就不会造成死锁 , 因此此时肯定有一个人能拿到两根筷子,当这个人吃完的时候, 就可以同时释放两个资源,那么就不会造成死锁现象的发生. 例如 两个线程两把锁的情况: 只需要约定好加锁顺序,不构造成线程1拿到锁 1, 线程2拿得到锁2 的情况即可. 每个人需要两根筷子,满足只允许4个人同时拿起筷子,那么就不会造成死锁 , 因此此时肯定有一个人能拿到两根筷子,当这个人吃完的时候, 就可以同时释放两个资源,那么就不会造成死锁现象的发生. 例如 两个线程两把锁的情况: 只需要约定好加锁顺序,不构造成线程1拿到锁 1, 线程2拿得到锁2 的情况即可. [590d1927fcde4d28b408229388e7022f.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/23/fdc9c1dba61a45eca63a993fa439cdf0.png [d9e8322bf2d341918f4c6cd384e78dff.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/23/97cba9e9547d44ca87049a9ca473f2fc.png [594d5a1ab5f44a4a90e582a44192035d.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/23/c951b31692014439be9a84ad91327a3b.png
相关 线程死锁的原因 造成线程死锁的原因以及解决方案 造成死锁的原因 一个线程一把锁 这种情况 可重入锁没事,不可重入锁会造成死锁, Java 中 synchronized是可重入 ゝ一世哀愁。/ 2024年03月23日 07:31/ 0 赞/ 43 阅读
相关 线程死锁 线程死锁是多线程中最头疼的问题,一旦进入线程死锁,很多时候只能通过外部进程重启才能解决问题 线程到达死锁的四个条件: 互斥条件:一个资源每次只能被一个线程使用 资源独占条 港控/mmm°/ 2022年08月21日 14:43/ 0 赞/ 209 阅读
相关 线程死锁 一、死锁概念 线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。当线程进入对象的synchronized代码块时,便 一时失言乱红尘/ 2022年06月14日 09:12/ 0 赞/ 264 阅读
相关 线程死锁的原因和解决办法 前言 死锁问题是多线程特有的问题,它可以被认为是线程间切换消耗系统性能的一种极端情况。在死锁时,线程间相互等待资源,而又不释放自身的资源,导致无穷无尽的等待,其结果是系统 妖狐艹你老母/ 2022年06月12日 05:16/ 0 赞/ 475 阅读
相关 线程死锁 简述: 星期一,新的的一周开始,天气晴朗,风和日丽。本是一个非常不错的心情,突然微信头像闪烁,果不其然又爬虫出问题了,可谓是一入爬虫深似海,项目稳定才见鬼。 墨蓝/ 2022年06月08日 06:30/ 0 赞/ 262 阅读
相关 Java——线程死锁 //要避免死锁 //死锁的例子 /class Ticket implements Runnable{ private int 我就是我/ 2022年06月07日 03:51/ 0 赞/ 264 阅读
相关 线程死锁 虽然同步锁机制解决了线程安全问题,但是也带来一些弊端: 1. 效率会降低,每次都需要判断锁的状态 2. 可能引发死锁(彼此占用所需要的资源),出现的概率非常小, 叁歲伎倆/ 2022年05月08日 02:38/ 0 赞/ 252 阅读
相关 线程死锁 先简单用生活列子介绍死锁, 2个人一起吃饭但是只有一双筷子,2人轮流吃(同时拥有2只筷子才能吃)。某一个时候,一个拿了左筷子,一人拿了右筷子,2个人都 ╰半夏微凉°/ 2022年04月08日 13:00/ 0 赞/ 276 阅读
相关 线程死锁 ![20190811092629898.png][] package com.vince; / 多线程要进行资源的共享,就需要同步,但同步过多,就 ゞ 浴缸里的玫瑰/ 2021年10月18日 09:36/ 0 赞/ 440 阅读
还没有评论,来说两句吧...