两个线程两次打印一个字符串的一个字符?

发布于 2025-02-10 17:03:28 字数 836 浏览 1 评论 0原文

我对以下任务有麻烦:

两个线程访问类的对象,并以相反顺序打印值 变量类型字符串的字母,字母,每个字母都用连字符打印 ( - )。示例:输入=名称。输出= eemmaann。

我做的是以下内容:

public class Print implements Runnable {
    private String string;
    Print(String string) {
        this.string = string;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i = string.length()-1; i >= 0; i--) {
   
            System.out.print(string.charAt(i) + "-");
                
        }
            
    }
    
}

public class Task1 {
    public static void main(String[] args) {
        Print r = new Print("NAME");
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.start();
        t2.start(); 
    }
}

它通常打印出Emaneman,但可能会有所不同。如何确保它始终打印出所需的结果?非常感谢

I have troubles with the following task:

Both threads access the object of the class Print and print in reverse order the value
of the variable type String, letter by letter, where each letter is printed with a hyphen
(–). Example : Input = NAME. Output = E-E-M-M-A-A-N-N.

What I've done is the following:

public class Print implements Runnable {
    private String string;
    Print(String string) {
        this.string = string;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i = string.length()-1; i >= 0; i--) {
   
            System.out.print(string.charAt(i) + "-");
                
        }
            
    }
    
}

public class Task1 {
    public static void main(String[] args) {
        Print r = new Print("NAME");
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.start();
        t2.start(); 
    }
}

And it prints usually E-M-A-N-E-M-A-N, but it can be different. How do I make sure that it always prints the desired result? Thank you very much

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不爱素颜 2025-02-17 17:03:28

正如我在评论中提到的那样,您需要cyclicbarrier,它将协调这两个线程,而不是让一个或另一个线程运行。

但是,如果您不希望打印最后的-字符,则需要在两个线程之间进行另一个协调,以i == 0。一个线程将打印最后一个字母加一个-,然后通知另一个线程以继续并打印最后一个字母。这可以使用原子变量和CountDownLatch来完成。谁赢得了原子变量的更新将打印字母折扣并计算闩锁,失败者将在闩锁上等待并打印字母。

class Print implements Runnable {
    private String string;

    private CyclicBarrier cb = new CyclicBarrier(2);
    private CountDownLatch cdl = new CountDownLatch(1);
    private AtomicBoolean win = new AtomicBoolean();

    Print(String string) {
        this.string = string;
    }
    @Override
    public void run() {
        try {
            for (int i = string.length()-1; i >= 0; i--) {
                cb.await();

                if (i != 0) {
                    System.out.print(string.charAt(i) + "-");
                } else {
                    if (win.getAndSet(true)) {
                        cdl.await();
                        System.out.print(string.charAt(i));
                    } else {
                        System.out.print(string.charAt(i) + "-");
                        cdl.countDown();
                    }
                }
            }
        } catch (Throwable ex) {
           ex.printStackTrace();
        }
    }
}

请注意,此设置仅适用于2个线程。

As I mentioned in the comment, you need CyclicBarrier, which will coordinate the two threads and not let one or the other run ahead.

However, if you don't want the last - character printed, there needs to be another coordination between the two threads for i == 0. One thread would print the last letter plus one -, then notify the other thread to go ahead and print just the last letter. This can be done with an atomic variable and a CountDownLatch. Who wins the update on the atomic variable will print letter-dash and count down the latch, the loser will wait on the latch and print the letter.

class Print implements Runnable {
    private String string;

    private CyclicBarrier cb = new CyclicBarrier(2);
    private CountDownLatch cdl = new CountDownLatch(1);
    private AtomicBoolean win = new AtomicBoolean();

    Print(String string) {
        this.string = string;
    }
    @Override
    public void run() {
        try {
            for (int i = string.length()-1; i >= 0; i--) {
                cb.await();

                if (i != 0) {
                    System.out.print(string.charAt(i) + "-");
                } else {
                    if (win.getAndSet(true)) {
                        cdl.await();
                        System.out.print(string.charAt(i));
                    } else {
                        System.out.print(string.charAt(i) + "-");
                        cdl.countDown();
                    }
                }
            }
        } catch (Throwable ex) {
           ex.printStackTrace();
        }
    }
}

Note that this setup works only for 2 threads.

我只土不豪 2025-02-17 17:03:28

它通常打印出Emaneman,但可能会有所不同。我如何确保它总是打印所需的结果?

而无需采取任何其他步骤,输出每次都会有所不同。第一个线程(t1)尽可能快地运行,并且该线程没有意识到print> print可运行的其他实例。

为了确保它始终打印所需的结果,您需要线程以某种方式坐标。在高级别上,逻辑看起来像:

  • 打印一个字母(第一次通过循环,给定输入“名称”)
  • 等待所有其他线程也打印其字母 - 正确的方法 几个内置同步选项之一
  • 一旦所有线程都同意该进行的

,他们每个人都可以进行一些操作以进行操作:使用 cyclicbarrier 或a phaser

这是一个示例,显示如何使用移相器解决此问题。

首先,这是每个线程的类。在构造函数中,它接受phaser,a list< string>(其中每个线程将添加输出)和字符串文本本身(ex:“ name”)。

class CoordinatedRunnable implements Runnable {

    private final Phaser phaser;
    private final List<String> outputBuffer;
    private final String text;

    CoordinatedRunnable(Phaser phaser, List<String> output, String text) {
        this.text = text;
        this.phaser = phaser;
        this.outputBuffer = output;

        phaser.register();
        new Thread(this).start();
    }

    @Override
    public void run() {
        for (int i = text.length() - 1; i >= 0; i--) {
            outputBuffer.add(String.valueOf(text.charAt(i)));
            phaser.arriveAndAwaitAdvance();
        }
        phaser.arriveAndDeregister();
    }
}

这是呼叫者的代码,使用文本“名称”并创建由同一移动器协调的2个线程。

Phaser phaser = new Phaser();
phaser.register();

List<String> outputBuffer = Collections.synchronizedList(new ArrayList<>());
String text = "NAME";
for (int i = 0; i < 2; i++) {
    new CoordinatedRunnable(phaser, outputBuffer, text);
}

// main loop advances through each phase, along with each worker thread
for (int i = 0; i < text.length(); i++) {
    phaser.arriveAndAwaitAdvance();
}

// reach here only when everyone is done with all phases
// print everything in the buffer, except for the last item
for (int i = 0; i < outputBuffer.size() - 1; i++) {
    System.out.print(outputBuffer.get(i) + "-");
}

// print the last item by itself, no delimiter
System.out.print(outputBuffer.get(outputBuffer.size() - 1));

这是输出:

E-E-M-M-A-A-N-N

由于移相器是唯一的协调点,因此它在2个以上的线程中也可以很好地工作。例如,这是带有10个线程的输出:

E-E-E-E-E-E-E-E-E-E-M-M-M-M-M-M-M-M-M-M-A-A-A-A-A-A-A-A-A-A-N-N-N-N-N-N-N-N-N-N

It prints usually E-M-A-N-E-M-A-N, but it can be different. How do I make sure that it always prints the desired result?

Without taking any additional steps, the output will vary each time. The first thread (t1) runs as quickly as it can, and the thread has no awareness that there maybe other instances of the Print Runnable.

To make sure it always prints the desired result, you need the threads to coordinate somehow. At a high level, the logic would look something like:

  • print a single letter ("E" on first pass through the loop, given input "NAME")
  • wait for all other threads to also print their letter – the correct way to do this is with one of several built-in synchronization options
  • once all threads agree that it's time to proceed, they can each proceed

A few options for how to proceed: use a CyclicBarrier or a Phaser.

Here's an example showing how to solving this by using a phaser.

First, this is the class for each thread. In the constructor, it accepts a Phaser, a List<String> (where each thread will add output), and the string text itself (ex: "NAME").

class CoordinatedRunnable implements Runnable {

    private final Phaser phaser;
    private final List<String> outputBuffer;
    private final String text;

    CoordinatedRunnable(Phaser phaser, List<String> output, String text) {
        this.text = text;
        this.phaser = phaser;
        this.outputBuffer = output;

        phaser.register();
        new Thread(this).start();
    }

    @Override
    public void run() {
        for (int i = text.length() - 1; i >= 0; i--) {
            outputBuffer.add(String.valueOf(text.charAt(i)));
            phaser.arriveAndAwaitAdvance();
        }
        phaser.arriveAndDeregister();
    }
}

Here is code for the caller, using text "NAME" and creating 2 threads coordinated by the same phaser.

Phaser phaser = new Phaser();
phaser.register();

List<String> outputBuffer = Collections.synchronizedList(new ArrayList<>());
String text = "NAME";
for (int i = 0; i < 2; i++) {
    new CoordinatedRunnable(phaser, outputBuffer, text);
}

// main loop advances through each phase, along with each worker thread
for (int i = 0; i < text.length(); i++) {
    phaser.arriveAndAwaitAdvance();
}

// reach here only when everyone is done with all phases
// print everything in the buffer, except for the last item
for (int i = 0; i < outputBuffer.size() - 1; i++) {
    System.out.print(outputBuffer.get(i) + "-");
}

// print the last item by itself, no delimiter
System.out.print(outputBuffer.get(outputBuffer.size() - 1));

Here's the output:

E-E-M-M-A-A-N-N

And since the phaser is the only coordination point, it also works great with more than 2 threads. For example, here is the output with 10 threads:

E-E-E-E-E-E-E-E-E-E-M-M-M-M-M-M-M-M-M-M-A-A-A-A-A-A-A-A-A-A-N-N-N-N-N-N-N-N-N-N
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文