java - 对LeetCode上的 “Print in Order”问题感到困惑

标签 java multithreading runnable

在多线程上,这应该是一个简单的问题:https://leetcode.com/problems/print-in-order/
“Foo的相同实例将传递给三个不同的线程。线程A将调用first(),线程B将调用second(),线程C将调用Third()。设计一种机制并修改程序以确保第二个()在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()。阅读documentation以了解如何使用它。
在阅读文档时,建议您阅读package documentation,以了解有关哪些功能可用于处理多线程代码的更多信息。

更新
为了更好地理解这一挑战,假设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类中,以确保以正确的顺序调用3个Runnable对象。
简单地将Thread.sleep()调用添加到这3个方法是不正确的解决方案,因为无论此线程在下面的测试之间可能在线程启动之间添加了多长时间的延迟,它都应运行。
您必须使用某种线程同步功能,例如monitorsLocksSynchronizers

关于java - 对LeetCode上的 “Print in Order”问题感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64274008/

相关文章:

java - Maven:无法执行目标 org.codehaus.mojo:sonar-maven-plugin:2.7.1:sonar

java - 任何计算机(多核或单核)都可以同时运行多个线程吗

java - 我们需要在我们的 UML 类图中添加接口(interface) Runnable 吗?

具有可序列化和可运行队列元素的 Java ThreadPoolExecutor(编译错误 : no suitable constructor found for. ..)

java - 是否可以在线程内更新属性

java - 为什么从 https 切换到 http 时我的 session ID (JSESSIONID) 会发生变化? java jsf

java - Java 中的嵌套 while 循环

java - 当 someObject 是字段范围变量时,为什么 Eclipse null 分析会忽略 null 检查语句 : if (someObject ! = null) {...}?

java - 以线程安全的方式更新ConcurrentHashMap

multithreading - 比较 GCD 与 performSelectorInBackground : dispatch_async not in background