Java中经常存在以下的需求,启动多个相同或者不同的线程,主线程需要等待所有的线程执行完才继续往下执行
要实现上面的需求,基本的思路: 创建一个计数器, 来记录线程的执行
有两种实现方法
方法1:
使用锁和计数器:需要有一个对象锁,作用一:保证这个计数器的线程安全,作用二:阻塞主线程,等待所有线程执行完再来唤醒主线程继续执行
方法2:
使用Java线程包中的CountDownLatch:不需要加锁, 不需要wait notify这么复杂
方法1:
package com.yaya.thread.threadCount.count;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestCount {
int count = 0;
int total = 0;
Object object = new Object();
void testCount() {
total = 10;
ExecutorService pool = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
final int j = i;
Runnable runnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
System.out.println("runnalbe:" + j);
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
synchronized (object) {
count++;
if (count == total) {
object.notify();
}
}
}
}
};
pool.execute(runnable);
}
synchronized (object) {
if (count != total) {
try {
object.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
System.out.println("end");
pool.shutdown();
}
public static void main(String[] args) {
TestCount testCount = new TestCount();
testCount.testCount();
}
}
方法2: CountDownLatch
package com.yaya.thread.threadCount.countDownLatch;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import com.yaya.thread.future.ThreadPoolUtil;
public class TestCountDownLatch {
static CountDownLatch count = null;
public void testRunnalbe(){
List<String> list = new ArrayList<String>();
for (int i = 1; i <= 10; i++) {
list.add("list" + i);
}
count = new CountDownLatch(list.size());
List<Runnable> runnables = new ArrayList<Runnable>();
for (int i = 0; i < list.size(); i++) {
final String listName = list.get(i);
Runnable runnable = new TestRunnable1(listName, count);
runnables.add(runnable);
}
try {
ThreadPoolUtil.exeRunnableList(runnables);
} catch (Exception e) {
System.err.println(e.getMessage());
}
try {
count.await();
System.out.println("end");
ThreadPoolUtil.shutDown(true);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void testDifferentRunnalbes(){
List<String> list = new ArrayList<String>();
for (int i = 1; i <= 10; i++) {
list.add("list" + i);
}
count = new CountDownLatch(list.size()*2);
List<Runnable> runnables = new ArrayList<Runnable>();
for (int i = 0; i < list.size(); i++) {
final String listName = list.get(i);
Runnable runnable = new TestRunnable1(listName, count);
runnables.add(runnable);
}
for (int i = 0; i < list.size(); i++) {
final String listName = list.get(i);
Runnable runnable = new TestRunnable2(listName, count);
runnables.add(runnable);
}
try {
ThreadPoolUtil.exeRunnableList(runnables);
} catch (Exception e) {
System.err.println(e.getMessage());
}
try {
count.await();
System.out.println("end");
ThreadPoolUtil.shutDown(true);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
TestCountDownLatch testCountDownLatch = new TestCountDownLatch();
testCountDownLatch.testDifferentRunnalbes();
}
}
package com.yaya.thread.threadCount.countDownLatch;
import java.util.concurrent.CountDownLatch;
public class TestRunnable2 implements Runnable {
String appid;
CountDownLatch count;
public TestRunnable2(String appid, CountDownLatch count) {
super();
this.appid = appid;
this.count = count;
}
@Override
public void run() {
System.out.println("task" + this.appid + "开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task" + this.appid + "睡了3s");
count.countDown();
}
}
package com.yaya.thread.future;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadPoolUtil {
// 线程池
private static ThreadPoolExecutor threadPool;
// 线程池核心线程数
private static final int CORE_POOL_SIZE = 5;
// 线程池最大线程数
private static final int MAX_POOL_SIZE = 10;
// 额外线程空状态生存时间
private static final int KEEP_ALIVE_TIME = 10000;
private static final int CANCEL_TASK_TIME = 20;
private ThreadPoolUtil() {
}
static {
threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(30), new ThreadFactory() {
private final AtomicInteger integer = new AtomicInteger();
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "mock thread:" + integer.getAndIncrement());
}
});
}
/**
* 从线程池中抽取线程,执行指定的Runnable对象
*
* @param runnable
*/
public static void execute(Runnable runnable) {
threadPool.execute(runnable);
}
/**
* 批量执行 Runnable任务
*
* @param runnableList
*/
public static void exeRunnableList(List<Runnable> runnableList) {
for (Runnable runnable : runnableList) {
threadPool.execute(runnable);
}
}
/**
* 从线程池中抽取线程,执行指定的Callable对象
*
* @param callable
* @return 返回执行完毕后的预期结果
*/
public static Future exeCallable(Callable<String> callable) {
return threadPool.submit(callable);
}
/**
* 批量执行 Callable任务
*
* @param callableList
* callable的实例列表
* @return 返回指定的预期执行结果
*/
public static List<Future<String>> exeCallableList(List<Callable<String>> callableList) {
List<Future<String>> futures = null;
try {
for (Callable<String> task : callableList) {
threadPool.submit(task);
}
futures = threadPool.invokeAll(callableList);
} catch (InterruptedException e) {
e.printStackTrace();
}
return futures;
}
/**
* 批量执行 Callable任务, 但不等待执行完
*
* @param callableList
* callable的实例列表
* @return 返回指定的预期执行结果
*/
public static void exeCallableListNoReturn(List<Callable<String>> callableList) {
for (Callable<String> task : callableList) {
threadPool.submit(task);
}
}
/**
* 中断任务的执行
*
* @param isForceClose
* true:强制中断 false:等待任务执行完毕后,关闭线程池
*/
public static void shutDown(boolean isForceClose) {
if (isForceClose) {
threadPool.shutdownNow();
} else {
threadPool.shutdown();
}
}
/**
* 若超出CANCEL_TASK_TIME的时间,没有得到执行结果,则尝试中断线程
*
* @param future
* @return 中断成功,则返回true 否则返回false
*/
public static boolean attemptCancelTask(Future future) {
boolean cancel = false;
try {
future.get(CANCEL_TASK_TIME, TimeUnit.MINUTES);
cancel = true;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
cancel = future.cancel(true);
e.printStackTrace();
}
return cancel;
}
}