天天看點

Java - 可重入鎖(也叫遞歸鎖)Java - 可重入鎖(也叫遞歸鎖)

Java - 可重入鎖(也叫遞歸鎖)

指的是同一個線程 外層 函數獲得鎖之後,内層 遞歸函數仍然能夠擷取該鎖的代碼,

在同一個線程在 外層方法 擷取鎖的時候,在進入 内層方法 會自動擷取鎖

也即是說,線程可以進入任何一個它已經擁有的鎖 所同步着的代碼塊。

Java - 可重入鎖(也叫遞歸鎖)Java - 可重入鎖(也叫遞歸鎖)
Java - 可重入鎖(也叫遞歸鎖)Java - 可重入鎖(也叫遞歸鎖)

synchronized 和 ReentrantLock 是可重入鎖的代碼證明

注意:

lock.lock(); 與 lock.unlock(); 這裡故意寫上兩次鎖并且解兩次鎖,代碼編譯沒有報錯,運作沒有報錯,程式正常退出

但是如果上鎖 和 解鎖 不是成對的,代碼編譯沒有問題,程式不能正常退出,因為死鎖了。

package com.test.mianshi.lock.可重入鎖;

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

/**
 * 可重入鎖(也叫遞歸鎖)
 * 指的是同一個外層函數獲得鎖之後,内層遞歸函數仍然能夠擷取該鎖的代碼
 * 在同一個線程在外層方法擷取鎖的時候,在進入内層方法會自動擷取鎖
 * <p>
 * 也即是說,線程可以進入任何一個它已經擁有鎖所同步的代碼塊
 *
 * case one 說明 synchronized 是一個典型的 可重入鎖
 *      t1 invoked,sendMsm()
 *      t1 ##### invoked,sendEmail()
 *      t2 invoked,sendMsm()
 *      t2 ##### invoked,sendEmail()
 *
 * case two 說明 ReentrantLock 是一個典型的 可重入鎖
 *      t3 invoked get()
 *      t3 ##### invoked set()
 *      t4 invoked get()
 *      t4 ##### invoked set()
 */
public class ReenterLockDemo {

    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();

        new Thread(() -> {
            phone.sendMsm();
        }, "t1").start();

        new Thread(() -> {
            phone.sendMsm();
        }, "t2").start();

        TimeUnit.SECONDS.sleep(1);
        System.out.println();
        System.out.println();

        Thread t3 = new Thread(phone, "t3");
        Thread t4 = new Thread(phone, "t4");

        t3.start();
        t4.start();

    }
}

class Phone implements Runnable{

    public synchronized void sendMsm() {
        System.out.println(Thread.currentThread().getName() + " invoked,sendMsm()");
        sendEmail();
    }

    public synchronized void sendEmail() {
        System.out.println(Thread.currentThread().getName() + " ##### invoked,sendEmail()");
    }

    Lock lock = new ReentrantLock();
    @Override
    public void run() {
        get();
    }

    // lock.lock(); 與 lock.unlock(); 這裡故意寫上兩次鎖并且解兩次鎖,代碼編譯沒有報錯,運作沒有報錯,程式正常退出
    // 但是如果上鎖 和 解鎖 不是成對的,代碼編譯沒有問題,程式不能正常退出,因為死鎖了。
    private void get() {
        lock.lock();
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " invoked get()");
            set();
        }finally {
            lock.unlock();
            lock.unlock();
        }
    }

    private void set() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " ##### invoked set()");
        }finally {
            lock.unlock();
        }
    }
}
           

繼續閱讀