1. 程式人生 > >java鎖機制的兩種實現synchronized 與ReentrantLock

java鎖機制的兩種實現synchronized 與ReentrantLock

java的多執行緒環境下併發是常見問題,這兩天看了鎖相關的問題,記錄下兩個簡單的用鎖實現等待/喚醒機制的demo。

1.synchronized方式實現等待/喚醒。

public class WaitAndNotify {
    private static boolean flag = true;
    private static Object lock = new Object();
    public static void main(String[] args) {
        Thread waitThread = new Thread(new Wait(), "WaitThread");
        waitThread.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread notifyThread = new Thread(new Notify(), "NotifyThread");
        notifyThread.start();
    }
    private static class Wait implements Runnable {
        @Override
        public void run() {
            synchronized (lock) {
                while (flag) {
                    System.out.println(Thread.currentThread() + " flag是true,wait。。" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread() + " flag是false,開始繼續工作" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            }
        }
    }
    private static class Notify implements Runnable {
        @Override
        public void run() {
            synchronized (lock){
                System.out.println(Thread.currentThread() + " 持有鎖,發出通知" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                lock.notifyAll();
                flag = false;
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

列印結果:

Thread[WaitThread,5,main] flag是true,wait。。18:55:28
Thread[NotifyThread,5,main] 持有鎖,發出通知18:55:29
Thread[WaitThread,5,main] flag是false,開始繼續工作18:55:34

分析:根據程式可以看到,大致的過程就是:WaitThread拿到lock物件的鎖,然後根據flag標記,自己呼叫了wait()方法,從而釋放鎖並進入WAITTING狀態。NotifyThread此時獲取了lock物件的鎖,然後進行notify操作,此時WaitThread被喚醒,但是,它不能立刻執行,因為喚醒執行緒NotifyThread還持有“該物件的同步鎖”。必須等到NotifyThread執行緒釋放了“物件的同步鎖”之後,也就是同步程式碼塊執行完以後,即睡眠5秒以後,等待執行緒WaitThread才能獲取到“物件的同步鎖”進而繼續執行。

2.ReentrantLock方式實現等待/喚醒。

public class ReenterLockCondition {
    private static ReentrantLock lock = new ReentrantLock();

    private static Condition condition = lock.newCondition();

    private static Runnable runnable = () -> {
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName() + "進入等待。。");
            condition.await();
            System.out.println(Thread.currentThread().getName() + "繼續執行");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    };

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(runnable, "thread--1");
        thread.start();

        Thread.sleep(2000);

        lock.lock();
        condition.signal();
        System.out.println("主執行緒發出訊號");
        lock.unlock();
    }
}

列印結果:

thread--1進入等待。。
主執行緒發出訊號
thread--1繼續執行

分析:這裡thread–1執行緒是等待執行緒,主執行緒就是喚醒想成。開始thread-1啟動,拿到鎖,然後進入等待並且釋放鎖,2秒後,主執行緒拿到鎖,然後發出訊號並釋放鎖,最後,thread–1繼續執行。

 

相比Synchronized,ReentrantLock類提供了一些高階功能,主要有以下3項:

        1.等待可中斷,持有鎖的執行緒長期不釋放的時候,正在等待的執行緒可以選擇放棄等待,這相當於Synchronized來說可以避免出現死鎖的情況。

        2.公平鎖,多個執行緒等待同一個鎖時,必須按照申請鎖的時間順序獲得鎖,Synchronized鎖非公平鎖,ReentrantLock預設的建構函式是建立的非公平鎖,可以通過引數true設為公平鎖,但公平鎖表現的效能不是很好。

        3.鎖繫結多個條件,一個ReentrantLock物件可以同時繫結對個物件。

參考:https://blog.csdn.net/i_am_kop/article/details/80958856

https://blog.csdn.net/chenchaofuck1/article/details/51045134