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,不会让主线程永远等待。
另外,await()方法还有一个实用的重载方法:public booleanawait(long timeout, TimeUnit unit),设置超时时间。
例如上面的代码,想要设置超时时间10秒,到了10秒无论是否倒数完成到0,都会不再阻塞主线程。返回值是boolean类型,如果是超时返回false,如果计数到达0没有超时返回true。
主线程等待线程池
Java线程池java.util.concurrent.ExecutorService是很好用的多线程管理方式。ExecutorService的一个方法boolean awaitTermination(long timeout, TimeUnit unit),即阻塞主线程,等待线程池的所有线程执行完成,用法和上面所说的CountDownLatch的public boolean await(long timeout,TimeUnit unit)类似,参数设置一个超时时间,返回值是boolean类型,如果超时返回false,如果线程池中的线程全部执行完成,返回true。
由于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)); } }