突发奇想-怎么写一个死锁?

3,518 阅读2分钟

刚把手头上的项目代码撸完,闲来看看博客,然后就看到了线程这块的东西。之前有简单的记录过线程和进行的零碎知识。
JAVA基础知识系列---进程、线程安全

看着看着就想着怎么能写一个死锁呢,打开eclipse,突然感觉无从下手;之前都是一直在解决阻塞、死锁这些问题,现在反过来去写一个死锁感觉有点莫名奇妙。。。

ok,写一个死锁就要有一种场景,并且满足死锁的条件。

  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
  • 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

首先要有竞争的资源,并且两个线程要同时都在等待对方释放资源。那我们先弄两个资源:

Object lock=new Object();
Object lock2=new Object();

然后有两个线程:

Tr1 tr1=new Tr1(lock, lock2);
Tr2 tr2=new Tr2(lock, lock2);
		
Thread t1=new Thread(tr1);
Thread t2=new Thread(tr2);

启动:

t1.start();
t2.start();

那么对于lock,lock2怎么再线程内部产生竞争关系呢?来看代码:

package com.glmapper.base.synchronize;

public class Tr1 implements Runnable {
	
	Object lock;
	Object lock2;

	public Tr1(Object lock,Object lock2){
		this.lock= lock;
		this.lock2= lock2;
	}
	@Override
	public void run() {
	    //获取lock
		synchronized (lock) {
			System.out.println(Thread.currentThread().getName()+"获取了lock锁");
			try {
				Thread.sleep(3000);
			} catch (Exception e) {
			}
			//获取lock2
			synchronized (lock2) {
				System.out.println(Thread.currentThread().getName()+"获取了lock2锁");
			}
		}
		
	}
}


public class Tr2 implements Runnable {
	
	Object lock;
	Object lock2;

	public Tr2(Object lock,Object lock2){
		this.lock= lock;
		this.lock2= lock2;
	}
	@Override
	public void run() {
	    //获取lock2
		synchronized (lock2) {
			System.out.println(Thread.currentThread().getName()+"获取了lock2锁");
			try {
				Thread.sleep(3000);
			} catch (Exception e) {
			}
			//获取lock
			synchronized (lock) {
				System.out.println(Thread.currentThread().getName()+"获取了lock锁");
			}
		}
		
	}
}

分析一下:当线程1获取lock时,线程2获取了lock2锁;然后线程1继续执行,到这里,

synchronized (lock2) {
	System.out.println(Thread.currentThread().getName()+"获取了lock2锁");
}

此时需要获取到lock2这个锁,但是lock2现在被线程2持有;同时,线程2也开始执行到:

synchronized (lock) {
	System.out.println(Thread.currentThread().getName()+"获取了lock锁");
}

此时线程2也在尝试获取lock这把锁,但是lock又被线程1持有了。两个线程都在等待对方释放资源,造成了死锁。OK,完成了。。。
当我准备关机时,发现还在等呢?

??那为什么呢?? 我们开看下发生了什么....

  • 通过jps来看下我们程序进程
  • 使用jstack -l 【pid】 来看下信息

两个线程都处于BLOCKED状态了...,继续往下看
found 1 deadlock.如我们所愿,死锁发生了!