1. 程式人生 > >Lock鎖和Condition條件

Lock鎖和Condition條件

淺談Synchronized:

  synchronized是Java的一個關鍵字,也就是Java語言內建的特性,如果一個程式碼塊被synchronized修飾了,當一個執行緒獲取了對應的鎖,執行程式碼塊時,其他執行緒

便只能一直等待,等待獲取鎖的執行緒釋放鎖,而獲取鎖的執行緒釋放鎖會有三種情況:

  1).獲取鎖的執行緒執行完該程式碼塊,然後執行緒釋放對鎖的佔有;

  2).執行緒執行發生異常,此時JVM會讓執行緒自動釋放鎖;

  3).呼叫wait方法,在等待的時候立即釋放鎖,方便其他的執行緒使用鎖.

Lock的特性:

  1).Lock不是Java語言內建的;

  2).synchronized是在JVM層面上實現的,如果程式碼執行出現異常,JVM會自動釋放鎖

,但是Lock不行,要保證鎖一定會被釋放,就必須將unLock放到finally{}中(手動釋放);

  3).在資源競爭不是很激烈的情況下,Synchronized的效能要優於ReetarntLock,但是在很激烈的情況下,synchronized的效能會下降幾十倍;

  4).ReentrantLock增加了鎖:

    a. void lock(); // 無條件的鎖;

    b. void lockInterruptibly throws InterruptedException;//可中斷的鎖;

解釋:  使用ReentrantLock如果獲取了鎖立即返回,如果沒有獲取鎖,當前執行緒處於休眠狀態,直到獲得鎖或者當前執行緒可以被別的執行緒中斷去做其他的事情;但是如果是synchronized的話,如果沒有獲取到鎖,則會一直等待下去;

    c. boolean tryLock();//如果獲取了鎖立即返回true,如果別的執行緒正持有,立即返回false,不會等待;

    d. boolean tryLock(long timeout,TimeUnit unit);//如果獲取了鎖立即返回true,如果別的執行緒正持有鎖,會等待引數給的時間,在等待的過程中,如果獲取鎖,則返回true,如果等待超時,返回false;

Condition的特性:

    1.Condition中的await()方法相當於Object的wait()方法,Condition中的signal()方法相當於Object的notify()方法,Condition中的signalAll()相當於Object的notifyAll()方法。不同的是,Object中的這些方法是和同步鎖捆綁使用的;而Condition是需要與互斥鎖/共享鎖捆綁使用的。

    2.Condition它更強大的地方在於:能夠更加精細的控制多執行緒的休眠與喚醒。對於同一個鎖,我們可以建立多個Condition,在不同的情況下使用不同的Condition。
    例如,假如多執行緒讀/寫同一個緩衝區:當向緩衝區中寫入資料之後,喚醒"讀執行緒";當從緩衝區讀出資料之後,喚醒"寫執行緒";並且當緩衝區滿的時候,"寫執行緒"需要等待;當緩衝區為空時,"讀執行緒"需要等待。      

      如果採用Object類中的wait(), notify(), notifyAll()實現該緩衝區,當向緩衝區寫入資料之後需要喚醒"讀執行緒"時,不可能通過notify()或notifyAll()明確的指定喚醒"讀執行緒",而只能通過notifyAll喚醒所有執行緒(但是notifyAll無法區分喚醒的執行緒是讀執行緒,還是寫執行緒)。  但是,通過Condition,就能明確的指定喚醒讀執行緒。

複製程式碼
package com.imooc.locks;

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

public class Task {
    
    private final Lock lock = new ReentrantLock();
    
    private final Condition addCondition = lock.newCondition();
    
    private final Condition subCondition = lock.newCondition();
    
    
    private static int num = 0;
    private List<String> lists = new LinkedList<String>();
    
    public void add() {
        lock.lock();
        
        try {
            while(lists.size() == 10) {//當集合已滿,則"新增"執行緒等待
                addCondition.await();
            }
            
            num++;
            lists.add("add Banana" + num);
            System.out.println("The Lists Size is " + lists.size());
            System.out.println("The Current Thread is " + Thread.currentThread().getName());
            System.out.println("==============================");
            this.subCondition.signal();
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {//釋放鎖
            lock.unlock();
        }
    }
    
    
    public void sub() {
        lock.lock();
        
        try {
            while(lists.size() == 0) {//當集合為空時,"減少"執行緒等待
                subCondition.await();
            }
            
            String str = lists.get(0);
            lists.remove(0);
            System.out.println("The Token Banana is [" + str + "]");
            System.out.println("The Current Thread is " + Thread.currentThread().getName());
            System.out.println("==============================");
            num--;
            addCondition.signal();
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    
}
複製程式碼複製程式碼
package com.imooc.locks;

public class AddThread implements Runnable {
    
    private Task task;
    
    public AddThread(Task task) {
        this.task = task;
    }

    @Override
    public void run() {
        task.add();
    }

}
複製程式碼複製程式碼
package com.imooc.locks;

public class SubThread implements Runnable {
    
    private Task task;
    
    public SubThread(Task task) {
        this.task = task;
    }

    @Override
    public void run() {
        task.sub();
    }

}
複製程式碼複製程式碼
package com.imooc.locks;

public class TestLock {
    
    public static void main(String[] args) {
        Task task = new Task();
        
        Thread t1=new Thread(new AddThread(task));
        Thread t3=new Thread(new AddThread(task));
        Thread t7=new Thread(new AddThread(task));
        Thread t8=new Thread(new AddThread(task));
        Thread t2 = new Thread(new SubThread(task));
        Thread t4 = new Thread(new SubThread(task));
        Thread t5 = new Thread(new SubThread(task));
        Thread t6 = new Thread(new SubThread(task));
        
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        t6.start();
        t7.start();
        t8.start();
    }

}
複製程式碼

 某次執行結果:

The Lists Size is 1
The Current Thread is Thread-0
==============================
The Token Banana is [add Banana1]
The Current Thread is Thread-4
==============================
The Lists Size is 1
The Current Thread is Thread-1
==============================
The Token Banana is [add Banana1]
The Current Thread is Thread-5
==============================
The Lists Size is 1
The Current Thread is Thread-3
==============================
The Lists Size is 2
The Current Thread is Thread-2
==============================
The Token Banana is [add Banana1]
The Current Thread is Thread-6
==============================
The Token Banana is [add Banana2]
The Current Thread is Thread-7
==============================