如何从不同的线程按一定顺序打印行?

vdzxcuhz  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(356)

关闭。这个问题需要细节或清晰。它目前不接受答案。
**想改进这个问题吗?**通过编辑这个帖子来添加细节并澄清问题。

18天前关门了。
改进这个问题
假设我们有一节课:

public class Foo {
  public void first() { print("first"); }
  public void second() { print("second"); }
  public void third() { print("third"); }
}

同一个foo示例将被传递给三个不同的线程。线程a将调用first(),线程b将调用second(),线程c将调用third()。设计一个机制并修改程序,以确保second()在first()之后执行,third()在second()之后执行。
我的完整解决方案如下所示:

class Foo {

    int threadNumber;

    public Foo() {
        this.threadNumber = 1;
    }

    synchronized public void first(Runnable printFirst) throws InterruptedException {
        while (threadNumber != 1) {
            wait();
        }
        // printFirst.run() outputs "first". Do not change or remove this line.
        printFirst.run();
        threadNumber++;
        notifyAll();
    }

    synchronized public void second(Runnable printSecond) throws InterruptedException {
        while (threadNumber != 2) {
            wait();
        }
        // printSecond.run() outputs "second". Do not change or remove this line.
        printSecond.run();
        threadNumber++;
        notifyAll();
    }

    synchronized public void third(Runnable printThird) throws InterruptedException {
        while (threadNumber != 3) {
            wait();
        }
        // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();
        threadNumber++;
        notifyAll();
    }
}

目前我不明白如何将runnable对象传递给synchronized方法(这是任务条件之一):

public class Main {
    public static void main(String[] args) {
        Foo foo = new Foo();
        CustomFirst customFirst = new CustomFirst();
        CustomSecond customSecond = new CustomSecond();
        CustomThird customThird = new CustomThird();

        try {
            foo.first(customFirst);
            foo.third(customThird);
            foo.second(customSecond);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
vuktfyat

vuktfyat1#

我想,这是leetcode的问题。
现在我不知道怎么通过 Runnable 对象到同步方法(这是任务条件之一):
这个 runnable 可能看起来像:

private static class PrintingRunnable implements Runnable {

    private final String string;

    public PrintingRunnable(String string) {
        this.string = string;
    }

    @Override
    public void run() {
        System.out.print(string);
    }
}

并作为:

foo.first(new PrintingRunnable("first"));
foo.second(new PrintingRunnable("second"));
foo.third(new PrintingRunnable("third"));

请注意,您不需要自己供货 Runnable s、 或创建 Thread 如果要解决问题,只需执行 first , second ,和 third 方法。
在 java , Runnable 只不过是一些可以 run . 它可以打印一些东西,或者做其他任何事情。
有可能leetcode并不真正打印任何东西,而是使用不同的东西来测试提交(对于那些试图解决问题的人来说,这并不重要)
但是如果你想在本地做,你可以使用 PrintingRunnable 上图:

public static void main(String[] args) throws InterruptedException {
    Foo foo = new Foo();

    new Thread(() -> {
        try {
            foo.third(new PrintingRunnable("third"));
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }
    }).start();
    new Thread(() -> {
        try {
            foo.first(new PrintingRunnable("first"));
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }
    }).start();
    new Thread(() -> {
        try {
            foo.second(new PrintingRunnable("second"));
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }
    }).start();
}
gt0wga4j

gt0wga4j2#

这种逐步方案的ad hock实现可以基于倒计时闩锁原语,如下所示:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class FooOrchestration {
    public static class Foo {
        public void first() { print("first"); }
        public void second() { print("second"); }
        public void third() { print("third"); }
    }

    static void print(String text) {
        System.out.println(text);
    }

    static class Step extends Thread {
        private final CountDownLatch starter = new CountDownLatch(1);
        private final List<Step> nextSteps = new ArrayList<>();
        private final Runnable action;

        Step(final Runnable action) {
            this.action = action;
        }

        @Override
        public void run() {
            try {
                starter.await(); // wait until someone kicks the starter with countDown()
                action.run();
                for (Step s : nextSteps) { // let's start the following steps
                    s.starter.countDown();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                for (Step s : nextSteps) { // let's propagate 
                    s.interrupt(); // the interruption
                }
            }
        }
    }

    public static void main(String[] args) throws Throwable {
        Foo foo = new Foo();

        Step firstStep = new Step(() -> foo.first());
        Step secondStep = new Step(() -> foo.second());
        Step thirdStep = new Step(() -> foo.third());

        firstStep.nextSteps.add(secondStep); // set sequence
        secondStep.nextSteps.add(thirdStep); // of execution

        thirdStep.start(); // order of start
        secondStep.start(); // doesn't
        firstStep.start(); // matter

        firstStep.starter.countDown(); // kick the starterof the first step
    }
}

此外,标准包java.concurrent提供了更通用和灵活的屏障移相器https://www.baeldung.com/java-phaser 它允许轻松构建多线程执行的不同和复杂场景。

相关问题