线程死锁 ╰半夏微凉° 2022-04-08 13:00 279阅读 0赞 ## 先简单用生活列子介绍死锁, ## ### 2个人一起吃饭但是只有一双筷子,2人轮流吃(同时拥有2只筷子才能吃)。某一个时候,一个拿了左筷子,一人拿了右筷子,2个人都同时占用一个资源,等待另一个资源,这个时候甲在等待乙吃完并释放它占有的筷子,同理,乙也在等待甲吃完并释放它占有的筷子,这样就陷入了一个死循环,谁也无法继续吃饭。。 ### # 总而言之 # ## 当前线程不释放资源 ## ## 当前线程拥有其他线程执行的资源 ## ## 当前线程等待执行其他线程的资源 ## # 锁顺序死锁 # * ### 线程A调用`method1()`方法,得到obj1锁 ### * ### **同时**线程B调用`methd2()`方法,得到obj2锁 ### * ### 线程A和线程B都继续执行,此时线程A需要obj2锁**才能继续往下**执行。此时线程B需要obj1锁**才能继续往下**执行。 ### * ### 但是:**线程A的**obj1**锁并没有释放,线程B的**obj2**锁也没有释放**。 ### * ### 所以他们都只能等待,而这种等待是无期限的-->永久等待-->死锁 ### /** * */ package demo3; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @author liuchaojun * @date 2018-12-14 上午11:02:50 */ public class Lock1 { public static void main(String[] args) { Object obj1 = new Object(); Object obj2 = new Object(); ExecutorService e = Executors.newFixedThreadPool(5); Task1 t = new Task1(obj1, obj2); for (int i = 0; i < 10; i++) { e.execute(t); } } } class Task1 implements Runnable{ private Object obj1; private Object obj2; /** * @param obj1 * @param obj2 */ public Task1(Object obj1, Object obj2) { super(); this.obj1 = obj1; this.obj2 = obj2; } /* (non-Javadoc) * @see java.lang.Runnable#run() */ @Override public void run() { // 得到obj1锁 synchronized (obj1) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // 得到obj2锁 synchronized (obj2) { System.out.println("111111111"); } } // 得到obj2锁 synchronized (obj2) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // 得到obj1锁 synchronized (obj1) { System.out.println("2222222222222"); } } } } # 第二种:动态锁顺序死锁 # * ### 线程A的用户accout转账给fromAccount ### * ### 线程B的用户fromAccount转账给accout用户 ### * ### 如果两个线程同时进行调用method1方法 ### * ### 那么就会发生死锁。 ### /** * */ package demo3; /** * @author liuchaojun * @date 2018-12-14 上午11:02:50 */ public class Lock2 { void method1(Object account, Object fromAccount) { synchronized (account) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // 得到obj2锁 synchronized (fromAccount) { System.out.println(account+"给"+fromAccount+"转账"); } } } public static void main(String[] args) { final Lock2 lock2 = new Lock2(); final Object obj1 = new Object(); final Object obj2 = new Object(); new Thread(new Runnable() { @Override public void run() { lock2.aa(obj1, obj2); } }).start(); new Thread(new Runnable() { @Override public void run() { lock2.aa(obj2, obj1); } }).start(); } } # 二、避免死锁的方法 # ## 避免死锁可以概括成三种方法: ## * ## **固定加锁的顺序**(针对锁顺序死锁) ## * ## **开放调用**(针对对象之间协作造成的死锁) ## * ## **使用定时锁**\-->`tryLock()` ## ## 如果等待获取锁时间超时,则**抛出异常而不是一直等待**! ## ## 如上面转账代码,我们根据hash值进行上锁,**固定加锁的顺序,**这样就可以解决锁顺序死锁的问题 ## /** * */ package demo3; /** * @author liuchaojun * @date 2018-12-14 上午11:02:50 */ public class Lock2 { private static final Object newObj = new Object(); void method1(Object account, Object fromAccount) { // 得到锁的hash值 int accountHash = System.identityHashCode(account); int fromAccountHash = System.identityHashCode(fromAccount); if (accountHash > fromAccountHash) { synchronized (account) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // 得到obj2锁 synchronized (fromAccount) { System.out.println(account + "给" + fromAccount + "转账"); } } } else if (accountHash < fromAccountHash) { synchronized (fromAccount) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // 得到obj2锁 synchronized (account) { System.out.println(account + "给" + fromAccount + "转账"); } } } else { synchronized (newObj) { synchronized (fromAccount) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // 得到obj2锁 synchronized (account) { System.out.println(account + "给" + fromAccount + "转账"); } } } } } public static void main(String[] args) { final Lock2 lock2 = new Lock2(); final Object obj1 = new Object(); final Object obj2 = new Object(); new Thread(new Runnable() { @Override public void run() { lock2.method1(obj1, obj2); } }).start(); new Thread(new Runnable() { @Override public void run() { lock2.method1(obj2, obj1); } }).start(); } } ## 使用定时锁 ## ### 使用显式Lock锁,在获取锁时使用`tryLock()`方法。当等待**超过时限**的时候,`tryLock()`不会一直等待,而是返回错误信息。 ### ### 使用`tryLock()`能够有效避免死锁问题~~![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI3MDI2NjAz_size_16_color_FFFFFF_t_70][] ### ## 2.4死锁检测 ## ## 虽然造成死锁的原因是因为我们设计得不够好,但是可能写代码的时候不知道哪里发生了死锁。 ## ## JDK提供了两种方式来给我们检测: ## 1. ## JconsoleJDK自带的图形化界面工具,使用JDK给我们的的工具JConsole ## 2. ## Jstack是JDK自带的命令行工具,主要用于线程Dump分析。 ## # # [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI3MDI2NjAz_size_16_color_FFFFFF_t_70]: /images/20220405/401544ecaca2495b8112d9aec3ac4ff0.png
相关 Java线程死锁 /\ \ 【线程死锁】 \ 原因:两个线程相互等待被对方锁定的资源 \/ 代码模拟: public class DeadLock { 骑猪看日落/ 2022年09月26日 02:18/ 0 赞/ 252 阅读
相关 线程死锁 线程死锁是多线程中最头疼的问题,一旦进入线程死锁,很多时候只能通过外部进程重启才能解决问题 线程到达死锁的四个条件: 互斥条件:一个资源每次只能被一个线程使用 资源独占条 港控/mmm°/ 2022年08月21日 14:43/ 0 赞/ 211 阅读
相关 线程死锁 一、死锁概念 线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。当线程进入对象的synchronized代码块时,便 一时失言乱红尘/ 2022年06月14日 09:12/ 0 赞/ 265 阅读
相关 线程死锁 简述: 星期一,新的的一周开始,天气晴朗,风和日丽。本是一个非常不错的心情,突然微信头像闪烁,果不其然又爬虫出问题了,可谓是一入爬虫深似海,项目稳定才见鬼。 墨蓝/ 2022年06月08日 06:30/ 0 赞/ 263 阅读
相关 Java——线程死锁 //要避免死锁 //死锁的例子 /class Ticket implements Runnable{ private int 我就是我/ 2022年06月07日 03:51/ 0 赞/ 267 阅读
相关 多线程死锁 峨眉山月半轮秋,影入平羌江水流 Java线程的死锁一直都是经典的多线程问题;因为不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都不能继续执行; 示例代码: た 入场券/ 2022年05月24日 04:09/ 0 赞/ 420 阅读
相关 线程死锁 虽然同步锁机制解决了线程安全问题,但是也带来一些弊端: 1. 效率会降低,每次都需要判断锁的状态 2. 可能引发死锁(彼此占用所需要的资源),出现的概率非常小, 叁歲伎倆/ 2022年05月08日 02:38/ 0 赞/ 254 阅读
相关 线程死锁 先简单用生活列子介绍死锁, 2个人一起吃饭但是只有一双筷子,2人轮流吃(同时拥有2只筷子才能吃)。某一个时候,一个拿了左筷子,一人拿了右筷子,2个人都 ╰半夏微凉°/ 2022年04月08日 13:00/ 0 赞/ 280 阅读
相关 线程死锁 ![20190811092629898.png][] package com.vince; / 多线程要进行资源的共享,就需要同步,但同步过多,就 ゞ 浴缸里的玫瑰/ 2021年10月18日 09:36/ 0 赞/ 443 阅读
还没有评论,来说两句吧...