1. 程式人生 > 其它 >Java多執行緒與併發程式設計——Condition、Callable&Future

Java多執行緒與併發程式設計——Condition、Callable&Future

前言

每天積累一點點,積跬步至千里。今天學習JUC包中的Condition、Callable&Future。

Condition等待與喚醒

  • JUC提供了這麼多的工具類,目的是讓我們對於程式中多執行緒環境下,對執行緒的控制,Conditon物件,用來讓指定的執行緒等待與喚醒,按照我們預期的順序執行,大白話就是,我們完全掌控執行緒的執行順序。注意:它必須和ReentrantLock重入鎖配合使用。
  • Condition用於替代wait()/notify()方法
    • notify只能隨機喚醒等待的執行緒,而Condition可以喚醒指定執行緒,這有利於更好的控制併發程式。

Condition核心方法

  • await()阻塞當前執行緒,直到signal()喚醒
  • signal()喚醒被await()的執行緒,從中斷處繼續執行
  • signalAll()喚醒所有被await()阻塞的執行緒

程式碼示例

  • 建立三個執行緒,分別列印123,為了效果明顯加了1000ms睡眠,正常情況下按順序列印肯定是123
  • 但是現在我們想要列印312,這時就可以利用Condition來實現控制,看下面程式碼
publicclassConditionSample{
publicstaticvoidmain(String[]args)throwsInterruptedException{
ReentrantLocklock=newReentrantLock();
Conditionc1=lock.newCondition();
Conditionc2=lock.newCondition();
newThread(()->{
lock.lock();
try{
c1.await();//阻塞當前執行緒
Thread.sleep(1000);
System.out.println(1);
}catch(InterruptedExceptione){
e.printStackTrace();
}finally{
lock.unlock();
}
}).start();
newThread(()->{
lock.lock();
try{
c2.await();//阻塞當前執行緒
Thread.sleep(1000);
System.out.println(2);
}catch(InterruptedExceptione){
e.printStackTrace();
}finally{
lock.unlock();
}
}).start();
newThread(()->{
lock.lock();
try{
Thread.sleep(1000);
System.out.println(3);
c1.signal();
c2.signal();
}catch(InterruptedExceptione){
e.printStackTrace();
}finally{
lock.unlock();
}
}).start();
}
}

我們通過ReentrantLock物件建立了2Condition物件c1c2.相當於兩個標記鎖,分別加在列印12的執行緒上,等3列印完成,再去控制先喚醒哪個,先喚醒哪個則哪個列印輸出,實現預期效果。

Callable&Future

  • Callable和Runnable一樣用來建立執行緒,區別在於Callable有返回值並且可以丟擲異常
  • Future是一個介面。它用於表示非同步計算的結果。提供了檢查計算是否完成的方法,以等待計算的完成,並獲取計算的結果。

程式碼示例

獲取10000以內所有的質數,單執行緒迴圈查詢的做法這裡就不做介紹了,看下面示例程式碼,我們可以通過多執行緒的方式去判斷是否為質數,然後將結果接收返回。這裡獲取質數的方法比較簡單,如果換成更為複雜的邏輯,多執行緒的效率優勢就會很明顯了。

publicclassFutureSample{
publicstaticvoidmain(String[]args){
ExecutorServiceexecutorService=Executors.newFixedThreadPool(10);
for(inti=2;i<=10000;i++){
Computorc=newComputor();
c.setNum(i);
Future<Boolean>result=executorService.submit(c);
try{
Booleanr=result.get();
if(r){
System.out.println(c.getNum());
}
}catch(InterruptedException|ExecutionExceptione){
e.printStackTrace();
}
}
executorService.shutdown();
}
}
classComputorimplementsCallable<Boolean>{
privateIntegernum;
publicIntegergetNum(){
returnnum;
}
publicvoidsetNum(Integernum){
this.num=num;
}
@Override
publicBooleancall()throwsException{
booleanisprime=true;
for(inti=2;i<num;i++){
if(num%i==0){
isprime=false;
break;
}
}
returnisprime;
}
}
  • Future是對用於計算的執行緒進行監聽,因為計算是在其他執行緒中執行的,所以這個返回結果的過程是非同步的
  • executorService.submit(c);c物件提交給執行緒池,如有空閒執行緒立即執行裡面的call方法
  • result.get();用於獲取返回值,如果執行緒內部的call沒有執行完成,則進入等待狀態,直到計算完成