1、前言
我们多线程处理任务的时候,有时候需要多线程都执行完成的情况下才能执行其他的任务。这种情况下我们就需要判断多线程什么时候执行完。有以下几种方法,大家可以根据情况自行选择
2、实现方案
2.1、方案:isTerminated
使用isTerminated来判断所有任务都已完成,会返回true。但是前提是启用shutdown顺序关闭。
package com.wzl.xman.servicea.service.impl;
import com.wzl.xman.servicea.service.ThreadBizService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Service
public class ThreadBizServiceImpl implements ThreadBizService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void threadBizMethod01(String groupName) throws Exception {
logger.info(groupName + "==threadBizMethod Start==");
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 2000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(500));
for (int i = 1; i <= 10; i++) {
MyThreadRunnable01 runnable = new MyThreadRunnable01(groupName, i * 1000);
executor.execute(runnable);
}
executor.shutdown();
while (true) {
if (executor.isTerminated()) {
System.out.println("所有的子线程都结束了!");
break;
}
Thread.sleep(1000);//休眠1秒钟
}
logger.info(groupName + "==threadBizMethod End==");
}
}
/**
* 线程处理类
*/
class MyThreadRunnable01 implements Runnable {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private long millis;
private String groupName;
public MyThreadRunnable01(String groupName, long millis) {
this.groupName = groupName;
this.millis = millis;
}
@Override
public void run() {
try {
logger.info(groupName + "开始处理业务!" + millis);
Thread.sleep(millis);
logger.info(groupName + "处理业务结束!" + millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
使用isTerminated来判断所有任务是否都已完成,需要先执行线程池的shutdown方法,对于线程池是共享的情况不是很友好!!!
2.2、方案:CountDownLatch
CountDownLatch是一个同步辅助类,用来判断多线程是否执行完成。
它的原理是先声明一个运行N个线程任务,每完成一个线程任务,计数器就减1。当计数器等于0,说明所有的多线程都运行完成了。
package com.wzl.xman.servicea.service.impl;
import com.wzl.xman.servicea.service.ThreadBizService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Service
public class ThreadBizServiceImpl implements ThreadBizService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private final static ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 2000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(500));
@Override
public void threadBizMethod02(String groupName) {
logger.info(groupName + "==threadBizMethod Start==");
CountDownLatch countDownLatch = new CountDownLatch(10);//确定会启动10个线程任务
for (int i = 1; i <= 10; i++) {
MyThreadRunnable runnable = new MyThreadRunnable(countDownLatch, groupName, i * 1000);
executor.execute(runnable);
}
try {
countDownLatch.await();//多线程运行结束前自旋等待
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info(groupName + "==threadBizMethod End==");
}
}
/**
* 线程处理类
*/
class MyThreadRunnable implements Runnable {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private long millis;
private String groupName;
private CountDownLatch countDownLatch;
public MyThreadRunnable(CountDownLatch countDownLatch, String groupName, long millis) {
this.countDownLatch = countDownLatch;
this.groupName = groupName;
this.millis = millis;
}
@Override
public void run() {
try {
logger.info(groupName + "开始处理业务!" + millis);
Thread.sleep(millis);
logger.info(groupName + "处理业务结束!" + millis);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();//计数器减1
}
}
}
2.3、方案:Future & Callable
Future & Callable 使线程具有返回值的功能,其中future.get() 个是阻塞方法,通过调用所有future的get()来判断线程是否全部结束。
package com.wzl.xman.servicea.service.impl;
import com.wzl.xman.servicea.service.ThreadBizService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Service
public class ThreadBizServiceImpl implements ThreadBizService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private final static ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 2000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(500));
@Override
public void threadBizMethod03(String groupName) {
logger.info(groupName + "==threadBizMethod Start==");
List<Future> futures = new ArrayList<Future>();
for (int i = 1; i <= 10; i++) {
MyCallable runnable = new MyCallable(groupName, i * 1000);
futures.add(executor.submit(runnable));
}
try {
for (Future<?> future : futures) {
String result = (String) future.get();//阻塞方法,获取线程返回结果
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
logger.info(groupName + "==threadBizMethod End==");
}
}
/**
* 线程处理类(带返回结果的)
*/
class MyCallable implements Callable<String> {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private long millis;
private String groupName;
public MyCallable(String groupName, long millis) {
this.groupName = groupName;
this.millis = millis;
}
@Override
public String call() throws Exception {
try {
logger.info(groupName + "开始处理业务!" + millis);
Thread.sleep(millis);
logger.info(groupName + "处理业务结束!" + millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
return groupName + "=" + millis;
}
}