目录
1.先写结果
使用FutureTask类即可实现判断线程池中的线程的状态,提供的方法是isDone(),get()。
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
2.判断某个线程是否执行完成(不使用线程池)
在不适用线程池的情况下,一般使用Thread类提供的isAlive方法来判断线程的状态。当线程开始处于活动状态时,返回true,当线程未开始或者已结束等其他状态,返回false。
public static void main(String[] args) {
Thread thread = new Thread(() -> System.out.println("线程开始执行"));
thread.start();
System.out.println(thread.isAlive());
//使用while循环判断线程是否执行完成
}
3.在线程池中不能使用isAlive判断线程状态的原因
3-1.错误示例
public static void main(String[] args) {
Thread task = new Thread(() -> {
System.out.println("线程1开始");
try {
Thread.sleep(10000); //10s
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread task2 = new Thread(() -> {
System.out.println("线程2开始");
try {
Thread.sleep(20000); //20s
} catch (InterruptedException e) {
e.printStackTrace();
}
});
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);
fixedThreadPool.execute(task);
fixedThreadPool.execute(task2);
fixedThreadPool.shutdown();
//判断线程池是否执行完成
while (!fixedThreadPool.isTerminated()) {
System.out.println("还在执行...");
if (task.isAlive()) { //理论上前10s这里应该是true,但是实际返回的是false
System.out.println("线程1执行完成");
}
if (task2.isAlive()) { //理论上前20s这里应该是true,但是实际返回的是false
System.out.println("线程2执行完成");
}
try {
Thread.sleep(2000); //2s
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("主线程结束");
}
原因:isAlive方法是针对于类来说的,当前Thread类是否执行过start方法就决定了isAlive方法返回的是否是true。而在线程池中,真正创建线程并运行的是ThreadFactory工厂类。
3-2.创建线程工厂
下面是创建Thread的源码,可以看到只是调用我们传入Runnable的run方法而已。这个返回的才是真正的在线程池中运行的线程。
public Thread newThread(final Runnable r) {
if (group.isDestroyed()) {
group = new ThreadGroup(group.getParent(), name + "-workqueue");
}
Runnable wrapped = new Runnable() {
public void run() {
++approxThreadCount;
try {
r.run();
} finally {
--approxThreadCount;
}
}
};
final Thread t = new Thread(group,
wrapped,
name + "-workqueue-" + threadNumber.getAndIncrement(),
0);
AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
t.setContextClassLoader(loader);
return true;
}
});
t.setDaemon(true);
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
3-3.创建线程方法(ThreadPoolExecutor)
ThreadPoolExecutor中创建线程(创建Worker时)。
private boolean addWorker(Runnable firstTask, boolean core) {
//firstTask就是我们一开始传入的类
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask); //调用了上面的创建工厂方法
final Thread t = w.thread; //得到了一个新的Thread
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start(); //启动了Thread,所以说我们传入的Thread压根没有执行,只是执行了我们的run方法
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
4.解决问题,实现判断线程池中的线程是否执行完成
4-1.FutureTask
使用idea的查看类继承结构(ctrl+alt+shift+U):
4-2.实现代码(使用isDone)
public static void main(String[] args) {
FutureTask<Boolean> futureTask = new FutureTask<>(() -> {
System.out.println("线程1开始");
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":线程1结束");
return true;
});
FutureTask<Boolean> futureTask1 = new FutureTask<>(() -> {
System.out.println("线程2开始");
try {
Thread.sleep(20 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":线程2结束");
return true;
});
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);
fixedThreadPool.execute(futureTask);
fixedThreadPool.execute(futureTask1);
fixedThreadPool.shutdown();
while (!fixedThreadPool.isTerminated()) {
System.out.println("还在执行...");
System.out.println("1:"+futureTask.isDone()); //前10s输出false,后10s输出true
System.out.println("2:"+futureTask1.isDone()); //20s输出false
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("1:"+futureTask.isDone()); //true
System.out.println("2:"+futureTask1.isDone()); //true
System.out.println("主线程结束");
}
使用isDone()来判断线程是否结束,不是NEW状态就返回true,包括线程已经取消或者异常
public boolean isDone() {
return state != NEW;
}
4-3.实现代码(使用get)
还可以通过get()方法来获取返回值,因为FutureTask是有返回值的,在线程执行完成之前,get()方法会一直处于堵塞状态。这样就可以在某个线程执行完成后再执行其他相关的代码。
public static void main(String[] args) {
FutureTask<Boolean> futureTask = new FutureTask<>(() -> {
System.out.println("线程1开始");
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":线程1结束");
return true;
});
FutureTask<Boolean> futureTask1 = new FutureTask<>(() -> {
System.out.println("线程2开始");
try {
Thread.sleep(20 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":线程2结束");
return true;
});
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);
fixedThreadPool.execute(futureTask);
fixedThreadPool.execute(futureTask1);
fixedThreadPool.shutdown();
try {
Boolean isSuccess = futureTask.get(); //10s后返回结果
System.out.println("获取到线程1执行结果:" + isSuccess);
Boolean isSuccess1 = futureTask1.get(); //20s后返回结果
System.out.println("获取到线程2执行结果:" + isSuccess1);
if (isSuccess && isSuccess1) {
System.out.println("线程执行完毕");
}
} catch (InterruptedException | ExecutionException e) {
System.out.println("线程异常");
}
System.out.println("主线程结束");
}
使用get()来获取线程的返回值,当获取到线程的返回值时,说明线程已经执行完毕。
get()方法的重载方法get(long timeout, TimeUnit unit)方法,可以设置最长堵塞时间,以免堵塞时间过长出现其他问题。
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
版权声明:本文为weixin_44269022原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。