Java 与三个线程的线程合作打印额外的数字

Java Thread Cooperation with Three Threads Prints Extra Numbers

我正在尝试通过三个线程打印三个 AP 序列(以 3 为增量),如下所示:

当任何其他线程轮流打印它们的序列号时,一个线程应该等待。线程应相互协作以从 1 到 LIMIT(整数;此处 LIMIT = 10)按顺序打印数字。

预期输出

(对于 LIMIT = 10)

1 (printed by Thread-1)
2 (printed by Thread-2)
3 (printed by Thread-3)
4 (printed by Thread-1)
5 (printed by Thread-2)
6 (printed by Thread-3)
7 (printed by Thread-1)
8 (printed by Thread-2)
9 (printed by Thread-3)
10 (printed by Thread-1)

实际输出

(对于 LIMIT = 10)

1 (printed by Thread-1)
2 (printed by Thread-2)
3 (printed by Thread-3)
4 (printed by Thread-1)
5 (printed by Thread-2)
6 (printed by Thread-3)
7 (printed by Thread-1)
8 (printed by Thread-2)
9 (printed by Thread-3)
10 (printed by Thread-1)
11 (printed by Thread-2)
12 (printed by Thread-3)

代码

class PrintingSequences {
    private static final int LIMIT = 10;
    int counter = 1;
    boolean isPrinting = false;

    // prints 1, 4, 7, 10, ...
    synchronized void printAPStartingFrom1() {
        while (counter <= LIMIT) {
            while (isPrinting || counter % 3 != 1) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println(e);
                    Thread.currentThread().interrupt();
                }
            }
            isPrinting = true;
            System.out.println(counter++ + " (printed by " + Thread.currentThread().getName() + ")");
            isPrinting = false;
            notifyAll();
        }
    }

    // prints 2, 5, 8, 11, ...
    synchronized void printAPStartingFrom2() {
        while (counter <= LIMIT) {
            while (isPrinting || counter % 3 != 2) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println(e);
                    Thread.currentThread().interrupt();
                }
            }
            isPrinting = true;
            System.out.println(counter++ + " (printed by " + Thread.currentThread().getName() + ")");
            isPrinting = false;
            notifyAll();
        }
    }

    // prints 3, 6, 9, 12, ...
    synchronized void printAPStartingFrom3() {
        while (counter <= LIMIT) {
            while (isPrinting || counter % 3 != 0) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println(e);
                    Thread.currentThread().interrupt();
                }
            }
            isPrinting = true;
            System.out.println(counter++ + " (printed by " + Thread.currentThread().getName() + ")");
            isPrinting = false;
            notifyAll();
        }
    }
}

public class TripleThreadCommunication {
    public static void main(String[] args) {
        PrintingSequences naturalNumbers = new PrintingSequences();

        new Thread("Thread-1") {
            @Override
            public void run() {
                naturalNumbers.printAPStartingFrom1();
            }
        }.start();

        new Thread("Thread-2") {
            @Override
            public void run() {
                naturalNumbers.printAPStartingFrom2();
            }
        }.start();

        new Thread("Thread-3") {
            @Override
            public void run() {
                naturalNumbers.printAPStartingFrom3();
            }
        }.start();
    }
}

程序有3个不同的synchronized方法:printAPStartingFrom1()printAPStartingFrom2()printAPStartingFrom3(),分别被Thread-1、Thread-2、Thread-3调用。线程使用 wait()notifyAll() 方法相互协作。

为什么输出始终包含两个超过给定限制 10 的额外数字,即 11 和 12?

线程被唤醒时(wait->runnable),需要重新判断当前counter是否小于LIMIT,否则,它将继续打印直到 while (counter <= LIMIT) 不成立。(这就是 1112 也被打印的原因)。

我建议你提前确定每个线程循环多少次(这样可以使代码更简单):

    // thread1
    // prints 1, 4, 7, 10, ...
    synchronized void printAPStartingFrom1() {
        int count = LIMIT % 3 == 0 ? LIMIT / 3 : LIMIT / 3 + 1;
        for (int i = 0; i < count; i++) {
            while (counter % 3 != 1) {
                wait();
            }
            printAndAddCounter();
            notifyAll();
        }
    }
    // thread2
    // prints 2, 5, 8, 11, ...
    synchronized void printAPStartingFrom1() {
        int count = (LIMIT - 1) % 3 == 0 ? LIMIT / 3 : LIMIT / 3 + 1;
        for (int i = 0; i < count; i++) {
            while (counter % 3 != 2) {
                wait();
            }
            printAndAddCounter();
            notifyAll();
        }
    }
    // thread3
    // prints 3, 6, 9, 12, ...
    synchronized void printAPStartingFrom1() {
        int count = LIMIT / 3;
        for (int i = 0; i < count; i++) {
            while (counter % 3 != 0) {
                wait();
            }
            printAndAddCounter();
            notifyAll();
        }
    }