package com.sysware.p2m.task.op.process; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; public class ThreadTese{ static class TestRnnubeal extends Thread{ private String threadName; private List<String> list; private int startIndex; private int endIndex; private CountDownLatch countDownLatch;//計數器 public TestRnnubeal(String threadName, List<String> list, int startIndex, int endIndex,CountDownLatch countDownLatch) { this.threadName = threadName; this.list = list; this.startIndex = startIndex; this.endIndex = endIndex; this.countDownLatch = countDownLatch; } public void run() { List<String> subList = list.subList(startIndex, endIndex); for(int i=0;i<subList.size();i++){ // System.out.println(i); } System.out.println(threadName+"處理了"+subList.size()+"條!startIndex:"+startIndex+"|endIndex:"+endIndex); countDownLatch.countDown();//計數器減1 } } public static void main(String[] args) { long strTime2 = System.currentTimeMillis(); List<String> tmpList = new ArrayList<String>(); for (int i = 0; i < 13000000; i++) { tmpList.add("test" + i); } int length = tmpList.size(); int num = 10; //初始線程數 //啓動多線程 if(num > length){ num = length; } int baseNum = length / num; int remainderNum = length % num; int end = 0; long end2 = System.currentTimeMillis(); long strTime = System.currentTimeMillis(); List<Thread> list =new ArrayList<Thread>(); CountDownLatch countDownLatch = new CountDownLatch(num); //建立一個線程計數器 傳入線程數 for (int i = 0; i < num; i++) { int start = end ; end = start + baseNum; if(i == (num-1)){ end = length; }else if( i < remainderNum){ end = end + 1; } Thread thread = new TestRnnubeal("線程[" + (i + 1) + "] ", tmpList,start , end,countDownLatch); thread.start(); // list.add(thread); //也能夠使用join方法; } // for (Thread thread:list){ // try { // thread.join(); // } catch (InterruptedException e) { // e.printStackTrace(); // } // }
try { boolean timeoutFlag = countDownLatch.await(50, TimeUnit.SECONDS);//設置線程超時時間 同await()同樣; if (timeoutFlag) { System.out.println("全部線程執行完畢"); }else { System.out.println("執行超時"); } // countDownLatch.await();//阻止主線程 當計數器爲0時放開(說明全部子線程以執行完畢) } catch (InterruptedException e) { e.printStackTrace(); }
long endTime = System.currentTimeMillis(); System.out.println("用時"+ (endTime-strTime) + "毫秒"+"處理數據用時"+(end2-strTime2)+"毫秒"); } }
注意:若是子線程中會有異常,那麼countDownLatch.countDown()應該寫在finally裏面,這樣才能保證異常後也能對計數器減1,不會讓主線程永遠等待。java
另外,await()方法還有一個實用的重載方法:public booleanawait(long timeout, TimeUnit unit),設置超時時間。多線程
例如上面的代碼,想要設置超時時間10秒,到了10秒不管是否倒數完成到0,都會再也不阻塞主線程。返回值是boolean類型,若是是超時返回false,若是計數到達0沒有超時返回true。併發
主線程等待線程池this
Java線程池java.util.concurrent.ExecutorService是很好用的多線程管理方式。ExecutorService的一個方法boolean awaitTermination(long timeout, TimeUnit unit),即阻塞主線程,等待線程池的全部線程執行完成,用法和上面所說的CountDownLatch的public boolean await(long timeout,TimeUnit unit)相似,參數設置一個超時時間,返回值是boolean類型,若是超時返回false,若是線程池中的線程所有執行完成,返回true。spa
因爲ExecutorService沒有相似CountDownLatch的無參數的await()方法,只能經過awaitTermination來實現主線程等待線程池。線程
public class Main { public static void main(String[] args) { long start = System.currentTimeMillis(); // 建立一個同時容許兩個線程併發執行的線程池 ExecutorService executor = Executors.newFixedThreadPool(2); for(int i = 0; i < 5; i++) { Thread thread = new TestThread(); executor.execute(thread); } executor.shutdown(); try { // awaitTermination返回false即超時會繼續循環,返回true即線程池中的線程執行完成主線程跳出循環往下執行,每隔10秒循環一次 while (!executor.awaitTermination(10, TimeUnit.SECONDS)); } catch (InterruptedException e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("子線程執行時長:" + (end - start)); } }