Java线程模拟死锁

之前一直存在一个误区:当某一个线程进入临界区,如果它无法继续运行下去而陷入阻塞,是会自动释放掉自身持有的锁。因而,在Java中很难出现循环等待而导致死锁。结果证明这是错的,下面的代码出现了Synchronization关键字的嵌套使用,发生了死锁:


public class TestDeadLock1 {



    public static void main(String[] args) {

        Thread t1 = new Thread(new MyThread5(0));

        Thread t2 = new Thread(new MyThread5(1));

        t1.start();

        t2.start();

    }

}



class MyThread5 implements Runnable{

    private static Object o1 = new Object();

    private static Object o2 = new Object();

    private int flag;



    public MyThread5(int flag) {

        this.flag = flag;

    }

    @Override

    public void run() {

        if(flag==0){

            synchronized (o1) {

                System.out.println(Thread.currentThread().getName()+"锁住了o1");

                try {
                    Thread.currentThread().sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (o2) {

                    System.out.println(Thread.currentThread().getName()+"执行结束");

                }

            }

        }else{

            synchronized (o2) {

                System.out.println(Thread.currentThread().getName()+"锁住了o2");

                try {
                    Thread.currentThread().sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (o1) {

                    System.out.println(Thread.currentThread().getName()+"执行结束");
                }
            }
        }
    }
}

打印结果:

Thread-1锁住了o2
Thread-0锁住了o1

一个线程通过synchronize关键字获取了某个对象的锁,当他继续请求其他对象的锁而陷入阻塞时,并不会释放掉它当前所持有的锁。

如果是lock的嵌套使用呢:

package thread.deadlock;


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**

 * 死锁示例

 * @author xiayunan

 * @date   2018年7月14日

 *

 */

public class TestDeadLock1 {



    public static void main(String[] args) {

        Thread t1 = new Thread(new MyThread5(0));

        Thread t2 = new Thread(new MyThread5(1));

        t1.start();

        t2.start();

    }

}



class MyThread5 implements Runnable{

    private static Lock l1 = new ReentrantLock();
    private static Lock l2 = new ReentrantLock();

    private int flag;



    public MyThread5(int flag) {

        this.flag = flag;

    }

    @Override

    public void run() {

        if(flag==0){


                l1.lock();

                System.out.println(Thread.currentThread().getName()+"锁住了l1");

                try {
                    Thread.currentThread().sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                l2.lock();

                    System.out.println(Thread.currentThread().getName()+"执行结束");

                l2.unlock();

                l1.unlock();

        }else{

               l2.lock();

                System.out.println(Thread.currentThread().getName()+"锁住了l2");

                try {
                    Thread.currentThread().sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                l1.lock();

                    System.out.println(Thread.currentThread().getName()+"执行结束");

                l1.unlock();

            l2.unlock();
        }
    }
}

打印出了类似的结果,可以得出类似的结论。

所以我们要在代码中,避免synchronize或者lock的嵌套使用。

现在来验证:如果一个线程获得了一个对象的锁,当因为某个条件无法再继续执行,通过调用wait()方法而陷入阻塞,它是否会释放掉它占有的锁?

/*
author:chxy
data:2020/3/23
description:
*/
package thread.deadlock;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class MyThread1 implements Runnable{

    private Lock lock = null;
    private Condition condition = null;

    MyThread1(Lock lock,Condition condition){
        this.lock = lock;
        this.condition = condition;
    }

    @Override
    public void run() {

            lock.lock();
            System.out.println("thread1 has come in");
            try {
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread1 has over");
            lock.unlock();
        }

}

class MyThread2 implements Runnable{

    private Lock lock = null;
    private Condition condition = null;

    MyThread2(Lock lock,Condition condition){
        this.lock = lock;
        this.condition = condition;
    }

    @Override
    public void run() {

        lock.lock();
            System.out.println("thread2 has come in,and i shall end first");
            condition.signal();
        lock.unlock();
    }
}

public class TestDeadLock2 {

    public static void main(String[] args) throws InterruptedException {

        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        Thread t1 = new Thread(new MyThread1(lock,condition));
        t1.start();

        Thread.currentThread().sleep(1000);

        Thread t2 = new Thread(new MyThread2(lock,condition));
        t2.start();
    }
}

打印的结果是:

thread1 has come in
thread2 has come in,and i shall end first
thread1 has over

证明:一个线程获得了一个对象的锁,当因为某个条件无法再继续执行,通过调用wait()方法而陷入阻塞,它是会释放掉它占有的锁。

坑:在synchronize代码块中无法使用wait和notify方法。只允许在synchronize方法中使用这两个方法,使线程因为等待某个条件而陷入阻塞或被因为条件满足而被唤醒。

 

你可能感兴趣的:(Java线程模拟死锁)