当前位置: 首页 > 知识库问答 >
问题:

对LeetCode上的“按顺序打印”问题感到困惑

微生承业
2023-03-14

这应该是多线程上的一个简单问题: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();
    }

**看来我可以用线程解决它。如下所示加入,但我不明白的是,为什么他们会将Runnable实例传递给每个方法,以及如何正确地执行,因为下面的代码将打印每条消息两次,一次是因为线程。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");
        }
    }```

共有2个答案

吉和同
2023-03-14

一个更简单的方法是使用Semaphorerun获取发布方法:

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();
    }
}
柴英博
2023-03-14

Leetcode是针对代码挑战的,所以我们不应该给出完整的解决方案,因为这对你来说不是挑战。

这里有一个提示:使用两个CountDownLatch对象,一个通知方法第二()方法first()完成,另一个通知方法第三()方法第二()完成。阅读留档以了解如何使用它。

在阅读文档的同时,我建议您阅读软件包文档,以进一步了解可用于处理多线程代码的功能。

更新

为了更好地理解这个挑战,假设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个可运行的对象。

只需添加线程。sleep()调用这3个方法并不是正确的解决方案,因为无论下面的测试在线程启动之间添加多长时间的延迟,都应该运行该方法。

您必须使用某种线程同步功能,例如监视器、锁或同步器。

 类似资料:
  • 1) 当我将它输入到python解释器中时,我得到的输出是“this”,然后是零除法错误。但是,我引用的站点提到函数调用是第二高的优先级,所以不是应该先执行print的两个函数调用吗?我知道有短路评估,但这不是只有当你达到and、nots和OR的优先级时才会起作用吗? 2) 有人能解释一下我遗漏了什么,以及如何判断python将按照什么顺序执行一个逻辑表达式吗?

  • 我正在尝试提出一种解决方案,它涉及在连接操作之后应用一些逻辑,从多个中的中选择一个事件。这类似于reduce函数,但它只返回1个元素,而不是递增地返回。因此最终结果将是单个(,对,而不是一个 每个键保证只到达一次。 假设像上面这样的连接操作,它用4个生成了1个,成功地连接并收集在。现在,我想做的是,立即访问这些值,并执行一些逻辑以将正确匹配到一个。例如,对于上面的数据集,我需要(,和)。 将为每个

  • 所以我一直在读Kafka的语义学,我对它的工作原理有点困惑。 我理解生产者如何避免发送重复的消息(以防代理的ack失败),但我不明白的是,在消费者处理消息但在提交偏移量之前崩溃的情况下,一次是如何工作的。Kafka不会在这种情况下重试吗?

  • 问题内容: 我可以理解以下定义: 每个对象都有一个标识,一个类型和一个值。一旦创建了对象,其身份就永远不会改变。您可能会认为它是对象在内存中的地址。所述操作者比较两个对象的身份; 该函数返回一个表示其身份的整数。 我认为上面的定义在创建“某物”时起作用,例如: 但是我不理解: 我还没有创建任何东西。那么整数“ 1”如何具有ID?这是否意味着只要我在Python Shell中“提及” 1,便立即将其

  • 问题内容: 我已经在eclipse中创建了一个项目,并添加了Maven依赖项。在Eclipse中,它表示我正在使用JRE 1.5。一切在Eclipse中都可以正常运行,例如,我可以运行测试。 当我尝试从终端运行时,出现以下错误。 …在-source 1.3中不支持泛型(使用-source 5或更高版本来启用泛型)… 看来,Maven认为我正在使用JRE 1.3,并且无法识别泛型或for-each循

  • 问题内容: 在碰到此链接http://www.javacodegeeks.com/2013/01/java-thread-pool-example-using- executors-and-threadpoolexecutor 之后,这是我第一次为新项目使用Java线程池。 .html ,我对此更加困惑,这是页面中的代码, 在代码中,创建了一个固定大小的池并创建了10个工作线程,对吗? 线程池应该