目录
- 死锁(Dead Lock)示例
- 解决方案1:顺序锁
- 解决方案2:轮询锁
死锁(Dead Lock)示例
两个线程
- 线程1:先获取锁A,再获取锁B
- 线程2:先获取锁B,再获取锁A
package com.example.demo;public class DeadLockExample {public static void main(String[] args) {Object lockA = new Object(); // 创建锁 AObject lockB = new Object(); // 创建锁 B// 创建线程 1Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (lockA) {System.out.println("线程 1:获取到锁 A!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程 1:等待获取 B...");synchronized (lockB) {System.out.println("线程 1:获取到锁 B!");}}}});t1.start(); // 运行线程// 创建线程 2Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (lockB) {System.out.println("线程 2:获取到锁 B!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程 2:等待获取 A...");synchronized (lockA) {System.out.println("线程 2:获取到锁 A!");}}}});t2.start(); // 运行线程}
}
程序会一直等待
线程 1:获取到锁 A!
线程 2:获取到锁 B!
线程 1:等待获取 B...
线程 2:等待获取 A...
解决方案1:顺序锁
两个线程
- 线程1:先获取锁A,再获取锁B
- 线程2:先获取锁A,再获取锁B
package com.example.demo;public class SolveDeadLockExample {public static void main(String[] args) {Object lockA = new Object(); // 创建锁 AObject lockB = new Object(); // 创建锁 B// 创建线程 1Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (lockA) {System.out.println("线程 1:获取到锁 A!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程 1:等待获取 B...");synchronized (lockB) {System.out.println("线程 1:获取到锁 B!");}}}});t1.start(); // 运行线程// 创建线程 2Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (lockA) {System.out.println("线程 2:获取到锁 A!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程 2:等待获取B...");synchronized (lockB) {System.out.println("线程 2:获取到锁 B!");}}}});t2.start(); // 运行线程}
}
程序执行完成
线程 1:获取到锁 A!
线程 1:等待获取 B...
线程 1:获取到锁 B!
线程 2:获取到锁 A!
线程 2:等待获取B...
线程 2:获取到锁 B!
解决方案2:轮询锁
两个线程
- 线程1:先获取锁A,再获取锁B,如果失败,则释放所有锁
- 线程2:先获取锁B,再获取锁A
package com.example.demo;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class SolveDeadLockExample {public static void main(String[] args) {Lock lockA = new ReentrantLock(); // 创建锁 ALock lockB = new ReentrantLock(); // 创建锁 B// 创建线程 1(使用轮询锁)Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {// 调用轮询锁pollingLock(lockA, lockB);}});t1.start(); // 运行线程// 创建线程 2Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {lockB.lock(); // 加锁System.out.println("线程 2:获取到锁 B!");try {Thread.sleep(1000);System.out.println("线程 2:等待获取 A...");lockA.lock(); // 加锁try {System.out.println("线程 2:获取到锁 A!");} finally {lockA.unlock(); // 释放锁}} catch (InterruptedException e) {e.printStackTrace();} finally {lockB.unlock(); // 释放锁}}});t2.start(); // 运行线程}/*** 轮询锁*/public static void pollingLock(Lock lockA, Lock lockB) {while (true) {if (lockA.tryLock()) { // 尝试获取锁System.out.println("线程 1:获取到锁 A!");try {Thread.sleep(1000);System.out.println("线程 1:等待获取 B...");if (lockB.tryLock()) { // 尝试获取锁try {System.out.println("线程 1:获取到锁 B!");} finally {lockB.unlock(); // 释放锁System.out.println("线程 1:释放锁 B.");break;}}} catch (InterruptedException e) {e.printStackTrace();} finally {lockA.unlock(); // 释放锁System.out.println("线程 1:释放锁 A.");}}// 等待一秒再继续执行try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
程序执行完成
线程 1:获取到锁 A!
线程 2:获取到锁 B!
线程 1:等待获取 B...
线程 2:等待获取 A...
线程 1:释放锁 A.
线程 2:获取到锁 A!
线程 1:获取到锁 A!
线程 1:等待获取 B...
线程 1:获取到锁 B!
线程 1:释放锁 B.
线程 1:释放锁 A.
参考文章
- 面试官:说一下顺序锁和轮询锁?