老板如何知道员工任务完成了?
想象你是一个公司老板(主线程),派了几个员工(子线程)去做项目。你怎么知道他们是否顺利完成工作?是天天盯着问?还是等他们主动汇报?Java中主线程监控子线程的状态,就面临着类似的挑战。今天我们就用职场的思维,彻底搞懂线程监控的几种实用方法!
一、基础版:线程自带的"体检报告"
每个Thread对象都自带状态查询功能,就像员工的打卡机:
Thread worker = new Thread(() -> {
// 子线程工作内容
});
worker.start();
// 主线程定期"查岗"
while(true) {
Thread.State state = worker.getState();
System.out.println("员工状态:" + state);
if(state == Thread.State.TERMINATED) {
System.out.println("工作完成!");
break;
}
Thread.sleep(1000); // 每隔1秒检查一次
}
状态类型说明:
- NEW:刚入职还没开始工作
- RUNNABLE:正在干活
- BLOCKED:等资源被卡住了
- WAITING:在等其他同事配合
- TIMED_WAITING:带计时器的等待
- TERMINATED:工作完成/被开除了
缺点:就像只看出勤记录,不知道工作质量(是否成功)
二、进阶版:让线程"主动汇报工作"
2.1 通过共享变量传递结果
// 共享的"工作报告"
AtomicBoolean success = new AtomicBoolean(false);
Thread worker = new Thread(() -> {
try {
// 模拟工作
Thread.sleep(2000);
success.set(true); // 工作成功
} catch (Exception e) {
success.set(false); // 工作失败
}
});
worker.start();
// 主线程等待并获取结果
worker.join(); // 等待员工下班
System.out.println("工作结果:" + (success.get() ? "成功" : "失败"));
2.2 使用回调接口(最符合职场思维)
// 定义"汇报接口"
interface Report {
void onResult(boolean success);
}
// 员工线程接受汇报接口
Thread worker = new Thread(() -> {
boolean result = doWork();
new Report() {
@Override
public void onResult(boolean success) {
System.out.println("主线程收到结果:" + success);
}
}.onResult(result);
});
worker.start();
三、高级版:使用JUC工具类(专业HR系统)
3.1 Future模式:像等快递一样等结果
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Boolean> future = executor.submit(() -> {
// 子线程工作
return doWork(); // 返回布尔结果
});
try {
boolean result = future.get(5, TimeUnit.SECONDS); // 最多等5秒
System.out.println("工作结果:" + result);
} catch (TimeoutException e) {
System.out.println("员工超时未完成!");
} catch (Exception e) {
System.out.println("工作出错:" + e.getMessage());
} finally {
executor.shutdown();
}
3.2 CountDownLatch:项目里程碑检查
CountDownLatch latch = new CountDownLatch(1); // 1个任务
new Thread(() -> {
try {
boolean success = doWork();
if(success) {
latch.countDown(); // 完成任务
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
// 主线程等待
boolean done = latch.await(3, TimeUnit.SECONDS);
System.out.println(done ? "按时完成" : "超时未完成");
四、异常处理:如何抓住线程的"小报告"
子线程异常不会自动传递给主线程,需要特殊处理:
4.1 传统try-catch
Thread worker = new Thread(() -> {
try {
doWork();
} catch (Exception e) {
System.err.println("子线程出错:" + e.getMessage());
}
});
4.2 使用UncaughtExceptionHandler
worker.setUncaughtExceptionHandler((t, e) -> {
System.out.println("抓到线程" + t.getName() + "的异常:" + e);
});
worker.start();
五、方案对比:不同场景如何选择?
方案 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
状态查询 | 简单监控 | 无需额外资源 | 无法获取执行结果 |
共享变量 | 需要知道成功/失败 | 简单直接 | 需要自己实现等待逻辑 |
Future | 需要超时控制 | JDK内置,功能完善 | 需要线程池支持 |
Callback | 异步回调场景 | 解耦性好 | 代码结构稍复杂 |
CountDownLatch | 多个子线程协同 | 可以等待多个线程 | 只能使用一次 |
六、最佳实践:代码怎么写?
6.1 使用CompletableFuture(Java8+)
CompletableFuture.supplyAsync(() -> doWork())
.thenAccept(result -> {
System.out.println("主线程收到结果:" + result);
})
.exceptionally(ex -> {
System.out.println("出错啦:" + ex.getMessage());
return null;
});
6.2 Spring的@Async注解(Spring项目)
@Async
public Future<Boolean> asyncTask() {
return new AsyncResult<>(doWork());
}
// 调用方
Future<Boolean> future = asyncTask();
boolean result = future.get();
结语:监控线程的"黄金法则"
- 简单监控用线程状态查询
- 需要结果用Future/Callback
- 超时控制务必加上
- 异常处理不能忘记
- 现代代码首选CompletableFuture
记住这个口诀:
线程监控不用愁,
多种方案任你求,
简单状态可查询,
要结果就用Future收,
异常处理不能漏,
最佳实践在前头!
思考题:如果子线程又创建了子线程(线程嵌套),如何监控最内层线程的执行结果?(提示:考虑Future的嵌套使用)
下期预告:《Java线程池的七大参数详解:从入门到调优实战》敬请期待!