Java多執行緒之執行緒協作
阿新 • • 發佈:2018-12-30
無意中在一篇文章中看到一個面試題,題目內容為:現有一個統計任務,需要3個執行緒完成,在這三個執行緒完成後由一個執行緒完成最後的統計報告工作,寫出大概程式碼。
其實多執行緒問題都可以從兩個角度考慮實現,一種是java5之前的同步關鍵字去實現,另一種是java5之後提供的多執行緒新特性角度去考慮。
對於傳統的同步關鍵字思路:四個執行緒都共享一個訊號量,當訊號量標誌子執行緒任務都完成時,喚醒最後的統計執行緒;對於java5併發包的思路:java5對於該類執行緒協作問題提供了CountDownLatch、CyclicBarrier、Semaphore等工具類,拿過來就可以用,這裡可以用CountDownLatch工具類,該工具類作用是某個任務需要等待其他幾個任務完成後才能開始執行。下面給出原始碼:
同步關鍵字:
package countdownlatch.Test2;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by dingxiangyong on 2016/3/25.
*/
public class Test {
public static void main(String[] args) {
Statistic statistic = new Statistic();
/**
* 訊號量
*/
Single single = new Single(3);
StatisticSubTask task1 = new StatisticSubTask(statistic, single);
StatisticSubTask task2 = new StatisticSubTask(statistic, single);
StatisticSubTask task3 = new StatisticSubTask(statistic, single);
StatisticAllTask taskAll = new StatisticAllTask(statistic, single);
ExecutorService service = Executors.newFixedThreadPool(4);
service.execute(task1);
service.execute(task2);
service.execute(task3);
service.execute(taskAll);
service.shutdown();
}
}
class StatisticSubTask implements Runnable{
private Statistic statistic;
private Single single;
public StatisticSubTask(Statistic statistic, Single single) {
this.statistic = statistic;
this.single = single;
}
@Override
public void run() {
try {
Thread.sleep(1000); //模擬統計耗時操作
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (statistic) {
statistic.result.add(new Object());
}
//減少訊號量
synchronized(single) {
single.countDown();
if (single.isEmpty()) {
single.notify();
}
}
}
}
class StatisticAllTask implements Runnable{
private Statistic statistic;
private Single single;
public StatisticAllTask(Statistic statistic, Single single) {
this.statistic = statistic;
this.single = single;
}
@Override
public void run() {
synchronized(single) {
//看訊號量,決定是否可以繼續處理
while(!single.isEmpty()) {
try {
single.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("result : " + statistic.result.size());
}
}
/**
* 統計結果
*/
class Statistic {
public List<Object> result = new ArrayList<Object>();
}
class Single {
private Integer count = 0;
public Single(Integer count) {
this.count = count;
}
public void countDown() {
this.count --;
}
public boolean isEmpty() {
return this.count == 0;
}
}
CountDownLatch實現:
package countdownlatch;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by dingxiangyong on 2016/3/25.
*/
public class Test {
public static void main(String[] args) {
/**
* 統計結果
*/
Statistic statictis = new Statistic();
/**
* 協同其他執行緒的鎖
*/
CountDownLatch latch = new CountDownLatch(3);
StatisticSubTask task1 = new StatisticSubTask(latch, statictis);
StatisticSubTask task2 = new StatisticSubTask(latch, statictis);
StatisticSubTask task3 = new StatisticSubTask(latch, statictis);
StatisticAllTask taskAll = new StatisticAllTask(latch, statictis);
ExecutorService service = Executors.newFixedThreadPool(4);
service.execute(task1);
service.execute(task2);
service.execute(task3);
service.execute(taskAll);
service.shutdown();
}
}
class StatisticSubTask implements Runnable {
/**
* 協同其他執行緒的鎖
*/
private CountDownLatch latch;
private Statistic statictis;
public StatisticSubTask(CountDownLatch latch, Statistic statictis) {
this.latch = latch;
this.statictis = statictis;
}
@Override
public void run() {
try {
Thread.sleep(1000); //模擬統計耗時操作
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (statictis) {
statictis.result.add(new Object());
}
latch.countDown(); //通知其他執行緒本執行緒任務已完成
}
;
}
class StatisticAllTask implements Runnable {
/**
* 協同其他執行緒的鎖
*/
private CountDownLatch latch;
private Statistic statictis;
public StatisticAllTask(CountDownLatch latch, Statistic statictis) {
this.latch = latch;
this.statictis = statictis;
}
@Override
public void run() {
try {
latch.await();//等待其他統計執行緒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("result : " + statictis.result.size());
}
;
}
/**
* 統計結果
*/
class Statistic {
public List<Object> result = new ArrayList<Object>();
}
對比程式碼,使用新特性CountDownLatch之後程式碼變得優雅許多。