Java并发编程 - 一个简单的死锁示例和死锁的检查
一个简单的死锁示例和死锁的检查
Java线程死锁是一个经典的多线程问题。因为不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法继续完成。
1.死锁程序示例
创建类 DeadLockThread:
public class DeadLockThread implements Runnable { private Object lock1 = new Object(); private Object lock2 = new Object(); private String s; public void setS(String s) { this.s = s; } @Override public void run() { if ("a".equalsIgnoreCase(s)) { synchronized (lock1) { System.out.println(Thread.currentThread() + " a 正在执行"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock2) { System.out.println("lock1 -> lock2 死锁未生效"); } } } if ("b".equalsIgnoreCase(s)) { synchronized (lock2) { System.out.println(Thread.currentThread() + " b 正在执行"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock1) { System.out.println("lock2 -> lock1 死锁未生效"); } } } } }
创建运行类 Main:
public class Main { public static void main(String[] args) throws InterruptedException { DeadLockThread deadLockThread = new DeadLockThread(); deadLockThread.setS("a"); Thread threadA = new Thread(deadLockThread); threadA.start(); Thread.sleep(200); deadLockThread.setS("b"); Thread threadB = new Thread(deadLockThread); threadB.start(); Thread.sleep(200); } }
运行结果如下:
2.使用JDK自带工具做死锁后的检查
1.进入JDK安装文件夹中的bin目录,执行jps命令:
得到正在运行着的线程Main的id值是12295。
2.在执行 jstack -l 12295 命令,查看结果:
由此结果可知,程序有死锁的现象。
3.使用IDEA的FindBugs插件检查可能出现的死锁
右键测试代码所在的包,选择分析包内文件
分析结果如下:
This method calls Thread.sleep() with a lock held. This may result in very poor performance and scalability, or a deadlock, since other threads may be waiting to acquire the lock. It is a much better idea to call wait() on the lock, which releases the lock and allows other threads to run.
此方法调用thread.sleep(),并保留一个锁。
这可能会导致性能和可伸缩性非常差,或者出现死锁,因为其他线程可能正在等待获取锁。
最好对锁调用wait(),这样可以释放锁并允许其他线程运行。
死锁是程序设计的bug,在设计程序时要避免双方互相持有对方锁的情况。需要说明的是,本实验使用synchronized嵌套的代码结构来实现死锁,其实不使用嵌套的synchronized代码结构也会出现死锁,与嵌套不嵌套没有任何的关系。只要互相等待对方释放锁,就有可能出现死锁。