java - 对 LeetCode 上的“按顺序打印”问题感到困惑
问题描述
这应该是多线程的一个简单问题:https ://leetcode.com/problems/print-in-order/ “Foo 的同一个实例将被传递给三个不同的线程。线程 A 将调用 first(),线程 B 将调用second(),线程C会调用third()。设计一种机制,修改程序,保证second()在first()之后执行,third()在second()之后执行”,他们给出了这段代码:
public Foo() {}
public void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
printFirst.run();
}
public void second(Runnable printSecond) throws InterruptedException {
// printSecond.run() outputs "second". Do not change or remove this line.
printSecond.run();
}
public void third(Runnable printThird) throws InterruptedException {
// printThird.run() outputs "third". Do not change or remove this line.
printThird.run();
}
**似乎我可以使用 Thread.join 解决它,如下所示,但我不明白的是为什么他们将 Runnable 的实例传递给每个方法,以及如何正确地做到这一点,因为下面的代码将打印每条消息两次 - 一次因为 Thread.start() 将调用相应的 run() 方法,并且一次直接调用该方法。我知道这是错误的方法,但是如果我们尝试使用 join 方法,则无法弄清楚什么是正确的解决方案。**
public Foo() throws InterruptedException {
Runnable r1 = () -> {
System.out.println("first ");
};
first(r1);
Runnable r2 = () -> {
System.out.println("second ");
};
second(r2);
Runnable r3 = () -> {
System.out.println("third ");
};
third(r3);
Thread t1 = new Thread(r1);
t1.start();
try {
t1.join(); // wait for this thread to finish before starting #2
}
catch(Exception e) {
System.err.println("Thread 1 error");
}
Thread t2 = new Thread(r2);
t2.start();
try {
t2.join();
}
catch(Exception e) {
System.err.println("Thread 2 error");
}
Thread t3 = new Thread(r3);
t3.start();
try {
t3.join();
}
catch(Exception e) {
System.err.println("Thread 3 error");
}
}```
解决方案
Leetcode 是针对代码挑战的,所以我们不应该给出完整的解决方案,因为那对你来说不会是一个挑战。
所以这里有一个提示:使用两个CountDownLatch
对象,一个通知方法second()
该方法first()
已完成,另一个通知方法third()
该方法second()
已完成。阅读文档以了解如何使用它。
在您阅读文档时,我建议您阅读包文档,以了解有关可用于处理多线程代码的功能的更多信息。
更新
为了更好地理解挑战,假设 Leetcode 正在使用这样的类来测试Foo
该类。
public class Test {
public static void main(String[] args) throws Exception {
Foo foo = new Foo();
Thread t1 = new Thread(() -> call(foo::first, "first,"));
Thread t2 = new Thread(() -> call(foo::second, "second,"));
Thread t3 = new Thread(() -> call(foo::third, "third."));
// Start threads out of order, with delay between them, giving each thread
// enough time to complete, if not adequately coded to ensure execution order.
t2.start();
Thread.sleep(500);
t3.start();
Thread.sleep(500);
t1.start();
// Wait for threads to complete
t2.join();
t3.join();
t1.join();
// At this point, the program output should be "first,second,third."
}
interface FooMethod {
public void call(Runnable printFirst) throws InterruptedException;
}
private static void call(FooMethod method, String text) {
try {
method.call(() -> System.out.print(text));
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
您无法修改此代码,因为它对您隐藏。您必须以某种方式向类中添加代码,Foo
以确保以Runnable
正确的顺序调用 3 个对象。
简单地添加Thread.sleep()
对 3 种方法的调用不是正确的解决方案,因为无论通过下面的这个测试在线程启动之间添加多长时间的延迟,它都应该运行。
推荐阅读
- spring-cloud-function - 使用 Spring Cloud Function 实现“生产列表 - 使用列表元素”
- java - 作为数组返回后无法通过方法传递整数值
- spring-boot - 在 Spring Boot 中将一个数据库平台切换到另一个数据库
- symfony5 - EasyAdmin 3 - 如果关联为空,则嵌套一对一表单?
- android - CERTIFICATE_VERIFY_FAILED:无效或不一致的证书扩展(handshake.cc.359)
- date - 如果 RPGLE 中的格式为 yyyy/mm/dd,如何测试(D)日期?
- postgresql - Postgres 使用 LOOP 和 RAISE 触发查询性能
- javascript - 使 Service Worker 始终从服务器加载文件,除非脱机
- typescript - worker_threads 中的 tsconfig 路径
- jquery - Ajax 更新不渲染 html