一、Synchronized
synchronized是Java的一個關鍵字,也就是Java語言内置的特性,如果一個代碼塊被synchronized修飾了,當一個線程擷取了對應的鎖,執行代碼塊時,其他線程便隻能一直等待,等待擷取鎖的線程釋放鎖,而擷取鎖的線程釋放鎖會有三種情況:
1. 擷取鎖的線程執行完該代碼塊,然後線程釋放對鎖的占有。
2. 線程執行發生異常,此時JVM會讓線程自動釋放鎖。
3. 調用wait方法,在等待的時候立即釋放鎖,友善其他的線程使用鎖.
二、Lock鎖
- Lock不是Java語言内置的。
- synchronized是在JVM層面上實作的,如果代碼執行出現異常,JVM會自動釋放鎖,但是Lock不行,要保證鎖一定會被釋放,就必須将unLock放到finally{}中(手動釋放)。
- 在資源競争不是很激烈的情況下,Synchronized的性能要優于ReetarntLock,但是在很激烈的情況下,synchronized的性能會下降幾十倍。
- ReentrantLock增加了鎖:
- void lock(); // 無條件的鎖。
- void lockInterruptibly throws InterruptedException; //可中斷的鎖。
- boolean tryLock(); //如果擷取了鎖立即傳回true,如果别的線程正持有,立即傳回false,不會等待。
- boolean tryLock(long timeout,TimeUnit unit); //如果擷取了鎖立即傳回true,如果别的線程正持有鎖,會等待參數給的時間,在等待的過程中,如果擷取鎖,則傳回true,如果等待逾時,傳回false。
- 使用ReentrantLock如果擷取了鎖立即傳回,如果沒有擷取鎖,目前線程處于休眠狀态,直到獲得鎖或者目前線程可以被别的線程中斷去做其他的事情;但是如果是synchronized的話,如果沒有擷取到鎖,則會一直等待下去。
三、Condition條件
- Condition中的await()方法相當于Object的wait()方法,Condition中的signal()方法相當于Object的notify()方法,Condition中的signalAll()相當于Object的notifyAll()方法。不同的是,Object中的這些方法是和同步鎖捆綁使用的;而Condition是需要與互斥鎖/共享鎖捆綁使用的。
- 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 = ;
private List<String> lists = new LinkedList<String>();
public void add() {
lock.lock();
try {
while(lists.size() == ) {//當集合已滿,則"添加"線程等待
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() == ) {//當集合為空時,"減少"線程等待
subCondition.await();
}
String str = lists.get();
lists.remove();
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();
}
}