java基础:详解synchronized可重入锁以及死锁的发生

1.什么是可重入锁?

  • 简单的来讲,可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁
  • 可重入,就是可以重复获取相同的锁

2.synchronized演示可重入锁代码示例如下

public class lock {

    public void test() {
        new Thread (() -> {
            synchronized (this){
                System.out.println ("获得lock对象锁");
                synchronized (this){
                    System.out.println ("获得lock对象锁");
                }
            }
        }).start ();
    }

    public static void main(String[] args) {
        new lock ().test ();
    }


}

控制台输出:

  • 获得lock对象锁
  • 获得lock对象锁

ps:由上实例可知,synchronized同步代码块在获取了lock对象锁后,并没有释放锁,接着执行了第二层synchronized代码块,得知synchronized是可重入锁,即第二处打印被执行。如果synchronized不是可重入锁,结果则会产生死锁。第二处打印将永远不会被执行!

public class lock {

    public void test() {
        new Thread (() -> {
            synchronized (this) {
                System.out.println ("线程一获得lock对象锁");
                try {
                    TimeUnit.SECONDS.sleep (100000L);
                } catch (InterruptedException e) {
                    e.printStackTrace ();
                }
                System.out.println ("555");
            }
        }).start ();

        new Thread (() -> {
            try {
                TimeUnit.SECONDS.sleep (2L);
            } catch (InterruptedException e) {
                e.printStackTrace ();
            }
            synchronized (this) {
                System.out.println ("线程二获得lock对象锁");
            }
        }).start ();

    }

    public static void main(String[] args) {
        new lock ().test ();
    }


}

控制台输入:

  • 线程一获得lock对象锁

ps:由于sleep不会释放对象锁,线程二一直在等待线程一释放对象锁,一旦线程一睡眠时间结束,释放了对象锁,线程二的同步代码块得到执行。说明synchronized可重入锁在同一线程中才可重入,不需要重新获取对象锁

3.演示死锁

public class lock {

    private Object lock1 = new Object ();

    private Object lock2 = new Object ();

    public void test() {
        new Thread (() -> {
            synchronized (lock1) {
                System.out.println ("线程一获得lock1对象锁");
                try {
                    TimeUnit.SECONDS.sleep (2L);
                } catch (InterruptedException e) {
                    e.printStackTrace ();
                }
                synchronized (lock2){
                    System.out.println ("线程一获得lock2对象锁");
                }
                System.out.println ("555");
            }
        },"t1").start ();

        new Thread (() -> {
            try {
                TimeUnit.SECONDS.sleep (1L);
            } catch (InterruptedException e) {
                e.printStackTrace ();
            }
            synchronized (lock2) {
                System.out.println ("线程二获得lock2对象锁");
                synchronized (lock1){
                    System.out.println ("线程二获得lock1对象锁");
                }
            }
        },"t2").start ();

    }

    public static void main(String[] args) {
        new lock ().test ();
    }


}

控制台输出:

  • 线程一获得lock1对象锁
  • 线程二获得lock2对象锁

ps:线程一获取了lock1对象锁,接着线程二获取了lock2对象锁,导致线程一无法获取lock2对象锁,线程二无法获取lock1对象锁,程序出现死锁。

4.使用jconsole查看

java基础:详解synchronized可重入锁以及死锁的发生_第1张图片

ps:lock1的拥有者为t2,lock2的拥有者为t1。相互争夺资源,程序产生死锁。 

 

你可能感兴趣的:(java)