赞
踩
1.1 什么是死锁?
1.2 死锁的影响
死锁的影响在不同系统中是不一样的,这取决于系统对死锁的处理能力
1.3 几率不高但危害大
2.1 最简单的情况
代码
- /**
- * MustDeadLock
- *
- * @author venlenter
- * @Description: 必定发生死锁的情况
- * @since unknown, 2020-06-10
- */
- public class MustDeadLock implements Runnable {
- int flag = 1;
- static Object o1 = new Object();
- static Object o2 = new Object();
-
- public static void main(String[] args) {
- MustDeadLock r1 = new MustDeadLock();
- MustDeadLock r2 = new MustDeadLock();
- r1.flag = 1;
- r2.flag = 0;
- Thread t1 = new Thread(r1);
- Thread t2 = new Thread(r2);
- t1.start();
- t2.start();
- }
- @Override
- public void run() {
- System.out.println("flag = " + flag);
- if (flag == 1) {
- synchronized (o1) {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (o2) {
- System.out.println("线程1成功拿到两把锁");
- }
- }
- }
- if (flag == 0) {
- synchronized (o2) {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (o1) {
- System.out.println("线程2成功拿到两把锁");
- }
- }
- }
- }
- }
-
- //输出结果
- flag = 1
- flag = 0
- //线程一直不解释,处于死锁状态
分析
- flag = 1
- flag = 0
-
- Process finished with exit code -1
2.2 实际生产中的例子:转账
- /**
- * TransferMoney
- *
- * @author venlenter
- * @Description: 转账时候遇到死锁,一旦打开注释,便会发生死锁
- * @since unknown, 2020-06-13
- */
- public class TransferMoney implements Runnable {
- int flag = 1;
- static Account a = new Account(500);
- static Account b = new Account(500);
-
- public static void main(String[] args) throws InterruptedException {
- TransferMoney r1 = new TransferMoney();
- TransferMoney r2 = new TransferMoney();
- r1.flag = 1;
- r2.flag = 0;
- Thread t1 = new Thread(r1);
- Thread t2 = new Thread(r2);
- t1.start();
- t2.start();
- t1.join();
- t2.join();
- System.out.println("a的余额" + a.balance);
- System.out.println("b的余额" + b.balance);
- }
-
- @Override
- public void run() {
- if (flag == 1) {
- transferMoney(a, b, 200);
- }
- if (flag == 0) {
- transferMoney(b, a, 200);
- }
- }
-
- public static void transferMoney(Account from, Account to, int amount) {
- synchronized (from) {
- // try {
- // Thread.sleep(500);
- // } catch (InterruptedException e) {
- // e.printStackTrace();
- // }
- synchronized (to) {
- if (from.balance - amount < 0) {
- System.out.println("余额不足,转账失败");
- }
- from.balance -= amount;
- to.balance += amount;
- System.out.println("成功转账" + amount + "元");
- }
- }
- }
-
- static class Account {
- public Account(int balance) {
- this.balance = balance;
- }
-
- int balance;
- }
- }
-
- //输出结果(没有死锁的情况)
- 成功转账200元
- 成功转账200元
- a的余额500
- b的余额500
-
- //开启备注的Thread.sleep则a和b线程死锁,没有输出,都在相互等待
2.3 模拟多人随机转账
- /**
- * MultiTransferMoney
- *
- * @author venlenter
- * @Description: 多人同时转账,依然很危险
- * @since unknown, 2020-06-13
- */
- public class MultiTransferMoney {
- private static final int NUM_ACCOUNTS = 500;
- private static final int NUM_MONEY = 1000;
- private static final int NUM_THREADS = 20;
- private static int NUM_ITERATIONS = 1000000;
-
- public static void main(String[] args) {
- Random rnd = new Random();
- Account[] accounts = new Account[NUM_ACCOUNTS];
- for (int i = 0; i < accounts.length; i++) {
- accounts[i] = new Account(NUM_MONEY);
- }
- class TransferThread extends Thread {
- @Override
- public void run() {
- for (int i = 0; i < NUM_ITERATIONS; i++) {
- int fromAcct = rnd.nextInt(NUM_ACCOUNTS);
- int toAcct = rnd.nextInt(NUM_ACCOUNTS);
- int amount = rnd.nextInt(NUM_MONEY);
- TransferMoney.transferMoney(accounts[fromAcct], accounts[toAcct], amount);
- }
- System.out.println("运行结束");
- }
- }
- for (int i = 0; i < NUM_THREADS; i++) {
- new TransferThread().start();
- }
- }
- }
- //输出结果(输出到一定时间后,20个线程都卡住了,死锁)
- 成功转账568元
- 成功转账129元
- 成功转账225元
- 成功转账623元
- ...
- 成功转账889元
- 余额不足,转账失败
- 成功转账451元
- 余额不足,转账失败
- 成功转账138元
- //所有线程卡住
4.1 使用java命令jstack(${JAVA_HOME}/bin/jstack pid)
- 1 package ConcurrenceFolder.mooc.threadConcurrencyCore.deadlock;
- 2
- 3 /**
- 4 * MustDeadLock
- 5 *
- 6 * @author venlenter
- 7 * @Description: 必定发生死锁的情况
- 8 * @since unknown, 2020-06-10
- 9 */
- 10 public class MustDeadLock implements Runnable {
- 11 int flag = 1;
- 12 static Object o1 = new Object();
- 13 static Object o2 = new Object();
- 14
- 15 public static void main(String[] args) {
- 16 MustDeadLock r1 = new MustDeadLock();
- 17 MustDeadLock r2 = new MustDeadLock();
- 18 r1.flag = 1;
- 19 r2.flag = 0;
- 20 Thread t1 = new Thread(r1);
- 21 Thread t2 = new Thread(r2);
- 22 t1.start();
- 23 t2.start();
- 24 }
- 25 @Override
- 26 public void run() {
- 27 System.out.println("flag = " + flag);
- 28 if (flag == 1) {
- 29 synchronized (o1) {
- 30 try {
- 31 Thread.sleep(500);
- 32 } catch (InterruptedException e) {
- 33 e.printStackTrace();
- 34 }
- 35 synchronized (o2) {
- 36 System.out.println("线程1成功拿到两把锁");
- 37 }
- 38 }
- 39 }
- 40 if (flag == 0) {
- 41 synchronized (o2) {
- 42 try {
- 43 Thread.sleep(500);
- 44 } catch (InterruptedException e) {
- 45 e.printStackTrace();
- 46 }
- 47 synchronized (o1) {
- 48 System.out.println("线程2成功拿到两把锁");
- 49 }
- 50 }
- 51 }
- 52 }
- 53}
-
- Found one Java-level deadlock:
- =============================
- "Thread-1":
- waiting to lock monitor 0x000000001be53948 (object 0x0000000780caf9a0, a java.lang.Object),
- which is held by "Thread-0"
- "Thread-0":
- waiting to lock monitor 0x000000001a93cd18 (object 0x0000000780caf9b0, a java.lang.Object),
- which is held by "Thread-1"
-
- Java stack information for the threads listed above:
- ===================================================
- "Thread-1":
- at ConcurrenceFolder.mooc.threadConcurrencyCore.deadlock.MustDeadLock.run(MustDeadLock.java:48)
- - waiting to lock <0x0000000780caf9a0> (a java.lang.Object)
- - locked <0x0000000780caf9b0> (a java.lang.Object)
- at java.lang.Thread.run(Thread.java:748)
- "Thread-0":
- at ConcurrenceFolder.mooc.threadConcurrencyCore.deadlock.MustDeadLock.run(MustDeadLock.java:36)
- - waiting to lock <0x0000000780caf9b0> (a java.lang.Object)
- - locked <0x0000000780caf9a0> (a java.lang.Object)
- at java.lang.Thread.run(Thread.java:748)
-
- Found 1 deadlock.
4.2 ThreadMXBean代码检测
- **
- * MustDeadLock
- *
- * @author venlenter
- * @Description: 用ThreadMXBean检测死锁
- * @since unknown, 2020-06-10
- */
- public class ThreadMXBeanDetection implements Runnable {
- int flag = 1;
- static Object o1 = new Object();
- static Object o2 = new Object();
-
- public static void main(String[] args) throws InterruptedException {
- ThreadMXBeanDetection r1 = new ThreadMXBeanDetection();
- ThreadMXBeanDetection r2 = new ThreadMXBeanDetection();
- r1.flag = 1;
- r2.flag = 0;
- Thread t1 = new Thread(r1);
- Thread t2 = new Thread(r2);
- t1.start();
- t2.start();
- Thread.sleep(1000);
- ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
- long[] deadLockedThreads = threadMXBean.findDeadlockedThreads();
- if (deadLockedThreads != null && deadLockedThreads.length > 0) {
- for (int i = 0; i < deadLockedThreads.length; i++) {
- ThreadInfo threadInfo = threadMXBean.getThreadInfo(deadLockedThreads[i]);
- System.out.println("发现死锁:" + threadInfo.getThreadName());
- }
- }
- }
- @Override
- public void run() {
- System.out.println("flag = " + flag);
- if (flag == 1) {
- synchronized (o1) {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (o2) {
- System.out.println("线程1成功拿到两把锁");
- }
- }
- }
- if (flag == 0) {
- synchronized (o2) {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (o1) {
- System.out.println("线程2成功拿到两把锁");
- }
- }
- }
- }
- }
-
- //输出结果
- flag = 1
- flag = 0
- 发现死锁:Thread-1
- 发现死锁:Thread-0
5.1 线上发生死锁应该怎么办?
5.2 常见修复策略
5.2.1 转账时避免死锁(转账换序方案)
- /**
- * TransferMoney
- *
- * @author venlenter
- * @Description: 转账时通过【hashcode】来决定获取锁的顺序,避免死锁
- * @since unknown, 2020-06-13
- */
- public class TransferMoney implements Runnable {
- int flag = 1;
- static Account a = new Account(500);
- static Account b = new Account(500);
- static Object lock = new Object();
-
- public static void main(String[] args) throws InterruptedException {
- TransferMoney r1 = new TransferMoney();
- TransferMoney r2 = new TransferMoney();
- r1.flag = 1;
- r2.flag = 0;
- Thread t1 = new Thread(r1);
- Thread t2 = new Thread(r2);
- t1.start();
- t2.start();
- t1.join();
- t2.join();
- System.out.println("a的余额" + a.balance);
- System.out.println("b的余额" + b.balance);
- }
-
- @Override
- public void run() {
- if (flag == 1) {
- transferMoney(a, b, 200);
- }
- if (flag == 0) {
- transferMoney(b, a, 200);
- }
- }
-
- public static void transferMoney(Account from, Account to, int amount) {
- //增加内部类
- class Helper {
- public void transfer() {
- if (from.balance - amount < 0) {
- System.out.println("余额不足,转账失败");
- }
- from.balance -= amount;
- to.balance += amount;
- System.out.println("成功转账" + amount + "元");
- }
- }
- int fromHash = System.identityHashCode(from);
- int toHash = System.identityHashCode(to);
- //通过通过【hashcode】来决定获取锁的顺序
- if (fromHash < toHash) {
- synchronized (from) {
- synchronized (to) {
- new Helper().transfer();
- }
- }
- } else if (fromHash > toHash) {
- synchronized (to) {
- synchronized (from) {
- new Helper().transfer();
- }
- }
- } else {
- //当hashcode相同的时候,冲突时需要“加时赛”,用额外的lock锁
- synchronized (lock) {
- synchronized (to) {
- synchronized (from) {
- new Helper().transfer();
- }
- }
- }
- }
- }
-
- static class Account {
- public Account(int balance) {
- this.balance = balance;
- }
-
- int balance;
- }
- }
5.2.2 哲学家就餐问题
(1)问题描述
- ①先拿起左手的筷子
- ②然后拿起右手的筷子
- ③如果筷子被人使用了,那就等别人用完
- ④吃完后,把筷子放回原位
(2)有【死锁】和【资源耗尽】的风险
(3)代码演示:哲学家进入死锁
- /**
- * DiningPhilosophers
- *
- * @author venlenter
- * @Description: 演示哲学家就餐问题导致的死锁
- * @since unknown, 2020-06-14
- */
- public class DiningPhilosophers {
- public static class Philosopher implements Runnable {
- private Object leftChopstick;
- private Object rightChopstick;
-
- public Philosopher(Object leftChopstick, Object rightChopstick) {
- this.leftChopstick = leftChopstick;
- this.rightChopstick = rightChopstick;
- }
-
- @Override
- public void run() {
- try {
- while (true) {
- doAction("Thinking");
- synchronized (leftChopstick) {
- doAction("Picked up left chopstick");
- synchronized (rightChopstick) {
- doAction("Pick up right chopstick - eating");
- doAction("Put down right chopstick");
- }
- doAction("Put down left chopstick");
- }
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- private void doAction(String action) throws InterruptedException {
- System.out.println(Thread.currentThread().getName() + " " + action);
- Thread.sleep((long) (Math.random() * 10));
- }
- }
-
- public static void main(String[] args) {
- Philosopher[] philosophers = new Philosopher[5];
- Object[] chopsticks = new Object[philosophers.length];
- for (int i = 0; i < chopsticks.length; i++) {
- chopsticks[i] = new Object();
- }
- for (int i = 0; i < philosophers.length; i++) {
- Object leftChopstick = chopsticks[i];
- Object rightChopstick = chopsticks[(i + 1) % philosophers.length];
- philosophers[i] = new Philosopher(leftChopstick, rightChopstick);
- new Thread(philosophers[i], "哲学家" + (i + 1) + "号").start();
-
- }
- }
- }
- //输出结果
- 哲学家1号 Thinking
- 哲学家2号 Thinking
- 哲学家3号 Thinking
- 哲学家4号 Thinking
- 哲学家5号 Thinking
- 哲学家2号 Picked up left chopstick
- 哲学家1号 Picked up left chopstick
- 哲学家5号 Picked up left chopstick
- 哲学家3号 Picked up left chopstick
- 哲学家4号 Picked up left chopstick
- //程序卡住,死锁
(4)多种解决方案
(5)代码演示:解决死锁
- /**
- * DiningPhilosophers
- *
- * @author venlenter
- * @Description: 演示哲学家就餐问题导致的死锁
- * @since unknown, 2020-06-14
- */
- public class DiningPhilosophers {
- public static class Philosopher implements Runnable {
- private Object leftChopstick;
- private Object rightChopstick;
-
- public Philosopher(Object leftChopstick, Object rightChopstick) {
- this.leftChopstick = leftChopstick;
- this.rightChopstick = rightChopstick;
- }
-
- @Override
- public void run() {
- try {
- while (true) {
- doAction("Thinking");
- synchronized (leftChopstick) {
- doAction("Picked up left chopstick");
- synchronized (rightChopstick) {
- doAction("Pick up right chopstick - eating");
- doAction("Put down right chopstick");
- }
- doAction("Put down left chopstick");
- }
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- private void doAction(String action) throws InterruptedException {
- System.out.println(Thread.currentThread().getName() + " " + action);
- Thread.sleep((long) (Math.random() * 10));
- }
- }
-
- public static void main(String[] args) {
- Philosopher[] philosophers = new Philosopher[5];
- Object[] chopsticks = new Object[philosophers.length];
- for (int i = 0; i < chopsticks.length; i++) {
- chopsticks[i] = new Object();
- }
- for (int i = 0; i < philosophers.length; i++) {
- Object leftChopstick = chopsticks[i];
- Object rightChopstick = chopsticks[(i + 1) % philosophers.length];
- //改进:当是最后一个哲学家,则反过来,先取右边的筷子
- if (i == philosophers.length - 1) {
- philosophers[i] = new Philosopher(rightChopstick, leftChopstick);
- } else {
- philosophers[i] = new Philosopher(leftChopstick, rightChopstick);
- }
- new Thread(philosophers[i], "哲学家" + (i + 1) + "号").start();
- }
- }
- }
- //输出结果
- //长时间打印,没有处于死锁状态
5.2.3 死锁检测与恢复策略
(1)检测算法:锁的调用链路图
(2)恢复方法1:【进程中止】
- ①优先级(是前台交互还是后台处理)
- ②已占用资源、还需要的资源(还需要一点资源就可以完成任务的,则优先执行,终止其他的)
- ③已运行时间(已运行较长时间,快要完成任务的,则优先执行,终止其他的)
(3)恢复方法2:资源抢占
6.1 设置【超时】时间
- /**
- * TryLockDeadlock
- *
- * @author venlenter
- * @Description: 用tryLock来避免死锁
- * @since unknown, 2020-06-14
- */
- public class TryLockDeadlock implements Runnable {
- int flag = 1;
- static Lock lock1 = new ReentrantLock();
- static Lock lock2 = new ReentrantLock();
-
- public static void main(String[] args) {
- TryLockDeadlock r1 = new TryLockDeadlock();
- TryLockDeadlock r2 = new TryLockDeadlock();
- r1.flag = 1;
- r2.flag = 0;
- new Thread(r1).start();
- new Thread(r2).start();
- }
-
- @Override
- public void run() {
- for (int i = 0; i < 100; i++) {
- if (flag ==1) {
- try {
- if (lock1.tryLock(800, TimeUnit.MILLISECONDS)) {
- System.out.println("线程1获取到了锁1");
- Thread.sleep(new Random().nextInt(1000));
- if (lock2.tryLock(800, TimeUnit.MILLISECONDS)) {
- System.out.println("线程1获取到了锁2");
- System.out.println("线程1成功获取到了两把锁,释放全部锁");
- lock2.unlock();
- lock1.unlock();
- break;
- } else {
- System.out.println("线程1尝试获取锁2失败,已重试,释放锁1");
- lock1.unlock();
- Thread.sleep(new Random().nextInt(1000));
- }
- } else {
- System.out.println("线程1获取锁1失败,已重试");
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- if (flag ==0) {
- try {
- if (lock2.tryLock(3000, TimeUnit.MILLISECONDS)) {
- System.out.println("线程2获取到了锁2");
- Thread.sleep(new Random().nextInt(1000));
- if (lock1.tryLock(3000, TimeUnit.MILLISECONDS)) {
- System.out.println("线程2获取到了锁1");
- System.out.println("线程2成功获取到了两把锁,释放全部锁");
- lock1.unlock();
- lock2.unlock();
- break;
- } else {
- System.out.println("线程2尝试获取锁1失败,已重试,释放锁2");
- lock2.unlock();
- Thread.sleep(new Random().nextInt(1000));
- }
- } else {
- System.out.println("线程2获取锁2失败,已重试");
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
- //输出结果
- 线程1获取到了锁1
- 线程2获取到了锁2
- 线程1尝试获取锁2失败,已重试,释放锁1
- 线程2获取到了锁1
- 线程2成功获取到了两把锁,释放全部锁
- 线程1获取到了锁1
- 线程1获取到了锁2
- 线程1成功获取到了两把锁,释放全部锁
6.2 多使用【并发类】而不是自己设计锁
6.3 尽量降低锁的使用【粒度】:用不同的锁而不是一个锁
6.4 如果能使用【同步代码块】,就不使用同步方法:方便自己指定锁对象,而不是直接整个方法
6.5 给线程起一个有意义的名字:debug和排查时事半功倍,框架和JDK都遵循这个最佳实践
6.6 避免锁的【嵌套】:MustDeadLock类
- synchronized(lock1) {
- synchronized(lock2) {
- //xxx
- }
- }
6.7 分配资源前先看下能不能收回来:银行家算法
6.8 尽量不要几个功能用同一把锁:【专锁专用】
7.1 活锁
7.1.1 什么是活锁
7.1.2 代码演示
- /**
- * LiveLock
- *
- * @author venlenter
- * @Description: 演示活锁问题
- * @since unknown, 2020-06-15
- */
- public class LiveLock {
- static class Spoon {
- private Diner owner;
-
- public Spoon(Diner owner) {
- this.owner = owner;
- }
-
- public Diner getOwner() {
- return owner;
- }
-
- public void setOwner(Diner owner) {
- this.owner = owner;
- }
-
- public synchronized void use() {
- System.out.printf("%s吃完了!", owner.name);
- }
- }
-
- static class Diner {
- private String name;
- private boolean isHunger;
-
- public Diner(String name) {
- this.name = name;
- isHunger = true;
- }
-
- public void eatWith(Spoon spoon, Diner spouse) {
- while (isHunger) {
- if (spoon.owner != this) {
- try {
- Thread.sleep(1);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- continue;
- }
- if (spouse.isHunger) {
- System.out.println(name + " : 亲爱的" + spouse.name + "你先吃吧");
- spoon.setOwner(spouse);
- continue;
- }
- spoon.use();
- isHunger = false;
- System.out.println(name + " : " + "我吃完了");
- spoon.setOwner(spouse);
- }
- }
- }
-
- public static void main(String[] args) {
- Diner husband = new Diner("牛郎");
- Diner wife = new Diner("织女");
- Spoon spoon = new Spoon(husband);
- new Thread(() -> husband.eatWith(spoon, wife)).start();
- new Thread(() -> wife.eatWith(spoon, husband)).start();
- }
- }
- //输出结果
- 牛郎 : 亲爱的织女你先吃吧
- 织女 : 亲爱的牛郎你先吃吧
- 牛郎 : 亲爱的织女你先吃吧
- 织女 : 亲爱的牛郎你先吃吧
- ...//一直循环交替输出,不停止
- 牛郎 : 亲爱的织女你先吃吧
- 织女 : 亲爱的牛郎你先吃吧
- 牛郎 : 亲爱的织女你先吃吧
- 织女 : 亲爱的牛郎你先吃吧
7.1.3 如何解决活锁问题
- /**
- * LiveLock
- *
- * @author venlenter
- * @Description: 演示活锁问题
- * @since unknown, 2020-06-15
- */
- public class LiveLock {
- static class Spoon {
- private Diner owner;
-
- public Spoon(Diner owner) {
- this.owner = owner;
- }
-
- public Diner getOwner() {
- return owner;
- }
-
- public void setOwner(Diner owner) {
- this.owner = owner;
- }
-
- public synchronized void use() {
- System.out.printf("%s吃完了!", owner.name);
- }
- }
-
- static class Diner {
- private String name;
- private boolean isHunger;
-
- public Diner(String name) {
- this.name = name;
- isHunger = true;
- }
-
- public void eatWith(Spoon spoon, Diner spouse) {
- while (isHunger) {
- if (spoon.owner != this) {
- try {
- Thread.sleep(1);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- continue;
- }
- Random random = new Random();
- //加入随机因素
- if (spouse.isHunger && random.nextInt(10) < 9) {
- System.out.println(name + " : 亲爱的" + spouse.name + "你先吃吧");
- spoon.setOwner(spouse);
- continue;
- }
- spoon.use();
- isHunger = false;
- System.out.println(name + " : " + "我吃完了");
- spoon.setOwner(spouse);
- }
- }
- }
-
- public static void main(String[] args) {
- Diner husband = new Diner("牛郎");
- Diner wife = new Diner("织女");
- Spoon spoon = new Spoon(husband);
- new Thread(() -> husband.eatWith(spoon, wife)).start();
- new Thread(() -> wife.eatWith(spoon, husband)).start();
- }
- }
- //输出结果
- 牛郎 : 亲爱的织女你先吃吧
- 织女 : 亲爱的牛郎你先吃吧
- 牛郎 : 亲爱的织女你先吃吧
- 织女吃完了!织女 : 我吃完了
- 牛郎吃完了!牛郎 : 我吃完了
7.1.4 工程中的活锁实例:【消息队列】
7.2 饥饿
(1)写一个【必然死锁】的例子,生产中什么场景下会发生死锁?
- /**
- * MustDeadLock
- *
- * @author venlenter
- * @Description: 必定发生死锁的情况
- * @since unknown, 2020-06-10
- */
- public class MustDeadLock implements Runnable {
- int flag = 1;
- static Object o1 = new Object();
- static Object o2 = new Object();
-
- public static void main(String[] args) {
- MustDeadLock r1 = new MustDeadLock();
- MustDeadLock r2 = new MustDeadLock();
- r1.flag = 1;
- r2.flag = 0;
- Thread t1 = new Thread(r1);
- Thread t2 = new Thread(r2);
- t1.start();
- t2.start();
- }
- @Override
- public void run() {
- System.out.println("flag = " + flag);
- if (flag == 1) {
- synchronized (o1) {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (o2) {
- System.out.println("线程1成功拿到两把锁");
- }
- }
- }
- if (flag == 0) {
- synchronized (o2) {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (o1) {
- System.out.println("线程2成功拿到两把锁");
- }
- }
- }
- }
- }
2、发生死锁必须满足【哪些条件】?
3、如何【定位】死锁
4、有哪些【解决】死锁问题的【策略】?
5、讲一讲经典的【哲学家就餐】问题
6、实际工程中如何【避免死锁】?
7、什么是活跃性问题?活锁、饥饿和死锁有什么区别?
笔记来源:慕课网悟空老师视频《Java并发核心知识体系精讲》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。