这时我学习总结的,写出了一个例子
死锁出现的情况:同步嵌套同步
死锁例子:
public class DeadLock implements Runnable {
private int flag; //标识线程交替
DeadLock(int flag){
this.flag = flag;
}
static Object o1 = new Object(),o2 = new Object(); //定义两把锁
public void run(){
System.out.println("flag=" + flag +"---"+ Thread.currentThread()); //打印当前线程信息
// 当flag==1锁住o1
if (flag == 1) {
synchronized (o1) {
System.out.println("101");
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
// 只要锁住o2就完成
synchronized (o2) {
System.out.println("1");
}
}
}
// 如果flag==0锁住o2
if (flag == 0) {
synchronized (o2) {
try {
System.out.println("202");
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
// 只要锁住o1就完成
synchronized (o1) {
System.out.println("0");
}
}
}
}
public static void main(String[] args) {
// 实例2个线程类
DeadLock td1 = new DeadLock(0);
DeadLock td2 = new DeadLock(1);
// 开启2个线程
Thread t1 = new Thread(td1);
Thread t2 = new Thread(td2);
t1.start();
t2.start();
}
}
运行结果:
flag=0--->Thread[Thread-0,5,main]
flag=1--->Thread[Thread-1,5,main]
202
101
或
flag=1--->Thread[Thread-1,5,main]
flag=0--->Thread[Thread-0,5,main]
101
202
理解:两个线程执行时,当Thread-0线程持有o1锁,线程Thread-1线程持有o2锁,
此时两个锁都没有释放,Thread-0线程嵌套的同步代码块要获取o2锁,Thread-1线程嵌套的同步代码块要获取o1锁,
但两个锁已被占用,均无法获取,程序到这里停止不动,就造成了死锁的情况
避免死锁:网络解释
让所有的线程按照同样的顺序获得一组锁。这种方法消除了 X 和 Y 的拥有者分别等待对方的资源的问题。
将多个锁组成一组并放到同一个锁下。前面Java线程死锁的例子中,可以创建一个银器对象的锁。于是在获得刀或叉之前都必须获得这个银器的锁。
将那些不会阻塞的可获得资源用变量标志出来。当某个线程获得银器对象的锁时,就可以通过检查变量来判断是否整个银器集合中的对象锁都可获得。如果是,它就可以获得相关的锁,否则,就要释放掉银器这个锁并稍后再尝试。
最重要的是,在编写代码前认真仔细地设计整个系统。多线程是困难的,在开始编程之前详细设计系统能够帮助你避免难以发现Java线程死锁的问题。 |