前言


我们来了解几个锁的概念,就是自旋锁、死锁、重入锁

一、重入锁


首先来看重入锁,也就是锁重入,什么意思呢?先说非重入锁

我们知道当多个线程来访问一个已经加了一个synchronized的方法的时候一个线程拿到我们的锁之后,那么,其他的线程就需要等待

image.png

当第一个线程执行完毕释放了这个锁之后,那么其他的线程才能够再进来

那么这就是说锁是不能够让所有的线程都进来的,只能有一个线程进来,然后其他的线程都在外面等着

image.png

那么锁重入是什么意思呢?比如说同一个实例中有两个方法都使用synchronized

那么第一个线程在第一个方法中获取了synchronized的锁,而在第一个方法里会去调用第二个方法,这时也是也可以的

image.png

我们才用代码模拟一下单线程下的这种个情况

class Demo1{

    public synchronized void a(){
        System.out.println("输出a");
        b();
    }

    public synchronized void b(){
        System.out.println("输出b");
    }
}
public static void main(String[] args) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            Demo1 demo1 = new Demo1();
            demo1.a();
        }
    }).start();
}
//运行结果如下:
输出a
输出b

而多线程的时候,是什么情况呢?使用代码来看看

public static void main(String[] args) {

        Demo1 demo1 = new Demo1();

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread()+"执行方法");
                demo1.b();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread()+"执行方法");
                demo1.a();
            }
        }).start();
}
//运行结果如下:
Thread[Thread-0,5,main]执行方法
输出b

Thread[Thread-1,5,main]执行方法
输出a
输出b

二、死锁


死锁之前有说过哲学家吃饭的问题,这里采用代码实践理解一下

当一个线程永远的持有一把锁,并且其他线程都尝试获得这把锁的时候,那么就发生了死锁

我们先创建两把锁看看怎么样

class Demo2{

    private Object object1 = new Object();

    private Object object2 = new Object();


    private  void a(){
        synchronized (object1){
        try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (object2){
                System.out.println("hi");
            }
        }
    }

    private  void b(){
        synchronized (object2){
            synchronized (object1){
                System.out.println("hi");
            }
        }
    }
}

接下来我们创建两个线程分别执行a与b方法看看

public static void main(String[] args) {
    Demo2 demo2 =new Demo2();
    new Thread(new Runnable() {
        @Override
        public void run() {
            demo2.a();
        }
    }).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            demo2.b();
        }
    }).start();
}

//运行结果如下:

程序卡在这里了产生了死锁,线程一执行a()方法拿到了obj1锁,线程二执行b()方法拿到了obj2锁

现在线程一没有释放obj1锁,于是第二个线程来请求obj1锁,那么就要等待

现在线程二在等待着,obj2锁肯定没有释放于是线程一又来请求obj2锁,所以线程一也处于等待状态

我们可以使用jconsole检测死锁,打开查看刚刚的死锁检测

image.png

参考资料


龙果学院:并发编程原理与实战(叶子猿老师)


28640
116 声望25 粉丝

心有多大,舞台就有多大