java執行緒學習(七):JDK併發包之Condition條件
阿新 • • 發佈:2019-01-09
在上一篇中,我們學習了JDK併發包的重入鎖的使用,然而執行緒流程的處理,並不單單是上鎖,中斷的操作,還有之前學到過的等待wait(),通知notify()等等,但wait(),notify()是與synchronized()搭配使用的。對應於jdk併發包,我們也有相應的類去使用,那就是重入鎖的好搭檔——Condition介面。
Condition介面有以下方法:
public interface Condition {
void await() throws InterruptedException;
void awaitUninterruptibly();
long awaitNanos(long var1) throws InterruptedException;
boolean await(long var1, TimeUnit var3) throws InterruptedException;
boolean awaitUntil(Date var1) throws InterruptedException;
void signal();
void signalAll();
}
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,就能明確的指定喚醒讀執行緒。
注:建議檢視之前的文章去了解下wait和notify的使用,後續對Condition的使用是很有幫助的。
Condition的使用(Condition是需要配合重入鎖使用的)
舉個例子:
package stop_demo;
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;
/**
* 例子說明:
* add()方法:當集合長度為10時,就掛起當前的執行緒, 讓其他執行緒先走。否則就會新增一條資訊,然後喚起執行sub()的執行緒
* sub()方法:當長度為0時,同理操作
*
* @author fei
*
*/
public class Condition_demo implements Runnable {
private final static Lock lock = new ReentrantLock();
private final static Condition addCondition = lock.newCondition();
private final static Condition subCondition = lock.newCondition();
private static int num = 0;
private static List<String> lists = new LinkedList<String>();
private boolean flag;
public Condition_demo(boolean flag){
this.flag=flag;
}
@Override
public void run() {
if (flag) {
add();//執行執行緒新增器
}
else {
sub();//執行執行緒減數器
}
}
public void add() {
lock.lock();
try {
while(lists.size() == 10) {//當集合已滿,則"新增"執行緒等待
addCondition.await();//滿了就掛起來
}
num++;
lists.add("add Banana" + num);
System.out.println("處於‘增加’執行緒方法 集合長度為: " + 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) {//當集合為空時,"減少"執行緒等待
System.out.println("‘減少’執行緒已掛起~~~~");
subCondition.await();
}
String str = lists.get(0);
lists.remove(0);
System.out.println("處於‘減少’執行緒方法: 集合內容為: [" + 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();
}
}
public static void main(String[] args) throws InterruptedException {
Condition_demo task1 = new Condition_demo(true);
Condition_demo task2 = new Condition_demo(false);
Thread t1 = new Thread(task1);
Thread t2 = new Thread(task1);
Thread t3 = new Thread(task1);
Thread t4 = new Thread(task1);
Thread t5 = new Thread(task1);
Thread t7 = new Thread(task2);
Thread t6 = new Thread(task2);
Thread t8 = new Thread(task2);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
t8.start();
}
}
可以複製當前例子到demo中,執行後就會發現,condition和lock真是個好搭檔!!