Java 困惑于;“按顺序打印”;LeetCode问题
这应该是多线程上的一个简单问题: “同一个Foo实例将被传递给三个不同的线程。线程A将调用first(),线程B将调用second(),线程C将调用third()。设计一个机制并修改程序,以确保second()在first()之后执行,third()在second()之后执行。”他们给出以下代码:Java 困惑于;“按顺序打印”;LeetCode问题,java,multithreading,runnable,Java,Multithreading,Runnable,这应该是多线程上的一个简单问题: “同一个Foo实例将被传递给三个不同的线程。线程A将调用first(),线程B将调用second(),线程C将调用third()。设计一个机制并修改程序,以确保second()在first()之后执行,third()在second()之后执行。”他们给出以下代码: public Foo() {} public void first(Runnable printFirst) throws InterruptedException { //
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()方法,另一次是因为Thread.start()会直接调用该方法。我知道这是一种错误的方法,但如果我们尝试使用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是针对代码挑战的,所以我们不应该给出完整的解决方案,因为这对您来说不是一个挑战 所以这里有一个提示:使用两个对象,一个通知方法
second()
方法first()
完成,另一个通知方法third()
方法second()
完成。阅读本手册,学习如何使用它
在阅读文档的同时,我建议您阅读,以进一步了解可用于处理多线程代码的功能
更新 为了更好地理解这个挑战,假设Leetcode使用这样的类来测试
Foo
类
公共类测试{
公共静态void main(字符串[]args)引发异常{
Foo-Foo=新的Foo();
线程t1=新线程(()->调用(foo::first,“first,”);
线程t2=新线程(()->调用(foo::second,“second”);
threadt3=新线程(()->调用(foo::third,“third.”);
//无序启动线程,线程之间有延迟,给每个线程
//如果没有充分编码以确保执行顺序,则有足够的时间完成。
t2.start();
睡眠(500);
t3.start();
睡眠(500);
t1.start();
//等待线程完成
t2.连接();
t3.join();
t1.join();
//此时,程序输出应为“第一、第二、第三”
}
接口方法{
公共void调用(Runnable printFirst)抛出InterruptedException;
}
私有静态void调用(FooMethod方法,字符串文本){
试一试{
方法调用(()->System.out.print(text));
}捕捉(中断异常e){
系统输出打印ln(e);
}
}
}
您无法修改此代码,因为它对您是隐藏的。您必须以某种方式将代码添加到Foo
类中,以确保以正确的顺序调用3个Runnable
对象
简单地向这3个方法添加Thread.sleep()
调用并不是正确的解决方案,因为无论下面的测试在线程启动之间添加了多长时间的延迟,这都应该运行
您必须使用某种线程同步功能,例如,或。Leetcode用于代码挑战,因此我们不应该给出完整的解决方案,因为这对您来说不会是一个挑战 所以这里有一个提示:使用两个对象,一个通知方法
second()
方法first()
完成,另一个通知方法third()
方法second()
完成。阅读本手册,学习如何使用它
在阅读文档的同时,我建议您阅读,以进一步了解可用于处理多线程代码的功能
更新 为了更好地理解这个挑战,假设Leetcode使用这样的类来测试
Foo
类
公共类测试{
公共静态void main(字符串[]args)引发异常{
Foo-Foo=新的Foo();
线程t1=新线程(()->调用(foo::first,“first,”);
线程t2=新线程(()->调用(foo::second,“second”);
threadt3=新线程(()->调用(foo::third,“third.”);
//无序启动线程,线程之间有延迟,给每个线程
//如果没有充分编码以确保执行顺序,则有足够的时间完成。
t2.start();
睡眠(500);
t3.start();
睡眠(500);
t1.start();
//等待线程完成
t2.连接();
t3.join();
t1.join();
//此时,程序输出应为“第一、第二、第三”
}
接口方法{
公共void调用(Runnable printFirst)抛出InterruptedException;
}
私有静态void调用(FooMethod方法,字符串文本){
试一试{
方法调用(()->System.out.print(text));
}捕捉(中断异常e){
系统输出打印ln(e);
}
}
}
您无法修改此代码,因为它对您是隐藏的。您必须以某种方式将代码添加到Foo
类中,以确保以正确的顺序调用3个Runnable
对象
简单地向这3个方法添加Thread.sleep()
调用并不是正确的解决方案,因为无论下面的测试在线程启动之间添加了多长时间的延迟,这都应该运行
您必须使用某种线程同步功能,例如,或。一种简单得多的方法是将
信号灯
与运行
,获取
,释放
方法一起使用:
class Foo {
Semaphore runSecond;
Semaphore runThird;
public Foo() {
runSecond = new Semaphore(0);
runThird = new Semaphore(0);
}
public void first(Runnable printFirst) throws InterruptedException {
printFirst.run();
runSecond.release();
}
public void second(Runnable printSecond) throws InterruptedException {
runSecond.acquire();
printSecond.run();
runThird.release();
}
public void third(Runnable printThird) throws InterruptedException {
runThird.acquire();
printThird.run();
}
}
一个简单得多的方法是将
信号灯
与run
,A一起使用