java多執行緒之 執行緒協作
阿新 • • 發佈:2018-11-08
也是網上看的一道題目:關於假如有Thread1、Thread2、Thread3、Thread4四條執行緒分別統計C、D、E、F四個盤的大小,所有執行緒都統計完畢交給Thread5執行緒去做彙總,應當如何實現?
蒐集整理了網上朋友提供的方法,主要有:
1. 多執行緒都是Thread或者Runnable(後者比較多),但是,這兩種都是沒返回值的,所以我們需要使用callable(有返回值的多執行緒)和future(獲得執行緒的返回值)來實現了。
public class TestThread { public static void main(String[] args) { ThreadCount tc = null; ExecutorService es = Executors.newCachedThreadPool();//執行緒池 CompletionService<Integer> cs = new ExecutorCompletionService<Integer>(es); for(int i=0;i<4;i++){ tc = new ThreadCount(i+1); cs.submit(tc); } // 新增結束,及時shutdown,不然主執行緒不會結束 es.shutdown(); int total = 0; for(int i=0;i<4;i++){ try { total+=cs.take().get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } System.out.println("總大小 = "+total); } } class ThreadCount implements Callable<Integer>{ private int type; ThreadCount(int type){ this.type = type; } @Override public Integer call() throws Exception { if(type==1){ System.out.println("C盤統計大小"); return 1; }else if(type==2){ System.out.println("D盤統計大小"); return 2; }else if(type==3){ System.out.println("E盤統計大小"); return 3; }else if(type==4){ System.out.println("F盤統計大小"); return 4; } return null; } }
輸出結果:
D盤統計大小
C盤統計大小
E盤統計大小
F盤統計大小
總大小 = 10
分析:四個執行緒實現的是Collable介面,執行完成後返回的值會存放與佇列中,用cs.take.get()獲取返回值獲取佇列中的值
2.用Java.util.concurrent下的方法解決
用CountDownLatch : 一個執行緒(或者多個), 等待另外N個執行緒完成某個事情之後才能執行
CountDownLatch 是計數器, 執行緒完成一個就記一個, 就像 報數一樣, 只不過是遞減的.
public class CountDownLatchDemo { final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static void main(String[] args) throws InterruptedException { CountDownLatch latch=new CountDownLatch(4);//兩個工人的協作 Worker worker1=new Worker("C", 1000, latch); Worker worker2=new Worker("D", 1000, latch); Worker worker3=new Worker("E", 1000, latch); Worker worker4=new Worker("F", 1000, latch); worker1.start();// worker2.start();// worker3.start();// worker4.start();// latch.await();//等待所有工人完成工作 System.out.println("all work done at "+sdf.format(new Date())); System.out.println(Worker.count); } static class Worker extends Thread{ static int count = 0; String workerName; int workTime; CountDownLatch latch; public Worker(String workerName ,int workTime ,CountDownLatch latch){ this.workerName=workerName; this.workTime=workTime; this.latch=latch; } public void run(){ synchronized (Worker.class) { System.out.println("Worker "+workerName+" do work begin at "+sdf.format(new Date())); int random = new Random().nextInt(5)+1; System.out.println("Worker "+workerName+" size = "+random); count = count + random; System.out.println("Worker "+workerName+" do work complete at "+sdf.format(new Date())); latch.countDown();//工人完成工作,計數器減一 } } } }
輸出結果:
Worker C do work begin at 2018-11-08 00:23:34 Worker C size = 5 Worker C do work complete at 2018-11-08 00:23:34 Worker F do work begin at 2018-11-08 00:23:34 Worker F size = 4 Worker F do work complete at 2018-11-08 00:23:34 Worker E do work begin at 2018-11-08 00:23:34 Worker E size = 1 Worker E do work complete at 2018-11-08 00:23:34 Worker D do work begin at 2018-11-08 00:23:34 Worker D size = 4 Worker D do work complete at 2018-11-08 00:23:34 all work done at 2018-11-08 00:23:34 14
分析:count中存放的是當前統計完成後的總大小,當4個盤的統計執行緒都完成以後,這個時候就可以執行執行緒5,這個與上面的區別是前面的執行緒執行完後沒有返回值,只能確定執行緒執行完成了,但卻沒有返回值。彙總統計沒有放線上程5中,前面4個統計執行緒執行完成以後,彙總統計結果已經出來了。