如何让线程等待Lambda表达式获取有效输入后再恢复执行?
解决线程等待Lambda获取用户输入的最优方案
你当前用wait/notify的思路是对的——这确实比轮询空转高效得多,但代码可以更简洁、更符合Java并发编程规范,这里给你几个优化方案:
方案1:优化现有wait/notify实现
你的代码存在几个潜在问题:比如handler数组未用volatile修饰,主线程可能看不到子线程赋值后的handler[0]导致空指针;还有wait被中断后的处理不够优雅;另外要注意虚假唤醒的问题。优化后的代码:
public class MRE { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // 用volatile保证主线程能看到子线程的赋值 volatile InputHandler handler = null; Thread thread = new Thread(() -> { Object lock = new Object(); boolean matches = false; synchronized (lock) { handler = (message) -> { synchronized (lock) { matches = message.equals("true"); lock.notify(); } }; try { // 用while循环判断条件,防止虚假唤醒 while (!matches) { lock.wait(); } } catch (InterruptedException e) { // 中断后重置线程中断状态,保证线程能正确退出 Thread.currentThread().interrupt(); return; } } // 拿到有效数据后执行后续逻辑 System.out.println("线程拿到结果:" + matches); }); thread.start(); // 等待handler初始化完成 while (handler == null) { Thread.yield(); } while (scanner.hasNext()) { handler.handleMessage(scanner.nextLine()); } } interface InputHandler { void handleMessage(String message); } }
方案2:用CountDownLatch(更直观的一次性等待)
CountDownLatch专门用来等待一个或多个事件完成,比wait/notify语义更清晰,代码也更简洁:
import java.util.Scanner; import java.util.concurrent.CountDownLatch; public class MRE { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); CountDownLatch latch = new CountDownLatch(1); boolean[] matches = new boolean[1]; InputHandler handler = message -> { matches[0] = message.equals("true"); latch.countDown(); // 触发latch,让等待的线程继续执行 }; Thread thread = new Thread(() -> { try { latch.await(); // 阻塞等待输入完成 } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } // 后续逻辑 System.out.println("线程拿到结果:" + matches[0]); }); thread.start(); while (scanner.hasNext()) { handler.handleMessage(scanner.nextLine()); } } interface InputHandler { void handleMessage(String message); } }
方案3:用CompletableFuture(Java 8+ 异步首选)
如果你的项目用Java 8及以上,CompletableFuture是更现代的选择,支持链式调用,无需手动管理线程:
import java.util.Scanner; import java.util.concurrent.CompletableFuture; public class MRE { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); CompletableFuture<Boolean> future = new CompletableFuture<>(); InputHandler handler = message -> { boolean result = message.equals("true"); future.complete(result); // 完成Future并传递结果 }; // 异步等待结果,自动处理线程 future.thenAccept(result -> { // 拿到结果后的逻辑 System.out.println("拿到结果:" + result); }); while (scanner.hasNext()) { handler.handleMessage(scanner.nextLine()); } } interface InputHandler { void handleMessage(String message); } }
总结
- 若需要最基础的并发控制,优化后的
wait/notify可满足需求,但要注意可见性和虚假唤醒问题; CountDownLatch适合一次性等待单个/多个事件的场景,语义清晰,代码简单;CompletableFuture适合Java 8+项目,尤其是需要异步链式处理的场景,是现代Java并发的首选。
内容的提问来源于stack exchange,提问作者blockgoblin31
相关产品推荐
相关产品推荐

