簡體   English   中英

一個使用多線程的簡短 Java 程序

[英]A short Java program that uses multiple threads

我正在嘗試編寫一個使用多個線程的簡短 Java 程序。 我希望主線程每 100 毫秒打印一次“i”。 並且子線程每 1000 毫秒打印一次“測試”。

結果應該是這樣的。

0,1,2,3,4,5,6,7,8,9,Test
10,11,12,13,14,15,16,17,18,19,Test
20,21,22,23,24,25,26,27,28,29,Test
30,31,32,33,34,35,36,37,38,39,Test
40,41,42,43,44,45,46,47,48,49,Test
50,51,52,53,54,55,56,57,58,59,Test
60,61,62,63,64,65,66,67,68,69,Test
70,71,72,73,74,75,76,77,78,79,Test
80,81,82,83,84,85,86,87,88,89,Test
90,91,92,93,94,95,96,97,98,99,Test

但我的結果是這樣的。

0,1,2,3,4,5,6,7,8,9,Test
10,11,12,13,14,15,16,17,18,Test
19,20,21,22,23,24,25,26,27,Test
28,29,30,31,32,33,34,35,36,Test
37,38,39,40,41,42,43,44,45,Test
46,47,48,49,50,51,52,53,54,Test
55,56,57,58,59,60,61,62,63,Test
64,65,66,67,68,69,70,71,72,Test
73,74,75,76,77,78,79,80,81,Test
82,83,84,85,86,87,88,89,90,91,Test
92,93,94,95,96,97,98,99,

這是我的完整代碼:

public class Main {
    public static void main(String[] args){
        Main.repeatTask(10, 1000);

        //print i, then sleep 100ms
        for(int i=0;i<100;i++){
            System.out.print(i + ",");
            try{
                Thread.sleep(100);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }

    //sleep (time)ms then print "Test"
    public static void repeatTask(int m, int time) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0; i < m; i++) {
                    try {
                        Thread.sleep(time);
                        System.out.println("Test");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

而且我無法更改主要方法。 如何更改我的方法 repeatTask?

這兩個線程是獨立的,也可能跑到不同的JVM,所以沒有什么可以保證你在另一個線程中的sleep() + 1000ms的喚醒將完全匹配主線程100ms睡眠的10倍。

如果您真的無法更改main方法,那么您可以創建自己的PrintStream實現(這是您在System.out中用於打印的內容):

public static class CustomPrintStream extends PrintStream {

    private final AtomicReference<CountDownLatch> latch;
    private final int repetitions;

    public CustomPrintStream(int repetitions) {
        super(System.out);
        this.repetitions = repetitions;
        this.latch = new AtomicReference<>(new CountDownLatch(repetitions));
    }

    @Override
    public void print(String s) {
        super.print(s);
        latch.get().countDown();
    }

    public void waitForLatch() throws InterruptedException {
        latch.get().await();
    }

    public void resetLatch() {
        latch.set(new CountDownLatch(repetitions));
    }
}

上述實現使用與 JVM 默認情況下相同的System.out ,除了它:

  1. 包含多次重復(在您的情況下10
  2. 包含對CountDownLatch的原子引用,該引用在10處初始化,並在每次觸及0時在10處重新初始化。

因此,您修改您的repeatTask方法如下:

public static void repeatTask(int m, int time) { //<-- note: you don't need time any longer
    CustomPrintStream customPrintStream = new CustomPrintStream(m); //<-- create your custom PrintStream with your number of repetitions
    System.setOut(customPrintStream); //<-- set it as the out for the JVM
    new Thread(() -> {
        for (int i = 0; i < m; i++) {
            try {
                customPrintStream.waitForLatch(); //<-- you wait for the countdown to 10 (the countdown is performed each time the main thread prints a number)
                System.out.println("Test"); //<-- hence you print Test
                customPrintStream.resetLatch(); //<-- and reset the countdown to 10
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

樣品 output:

0,1,2,3,4,5,6,7,8,9,Test
10,11,12,13,14,15,16,17,18,19,Test
20,21,22,23,24,25,26,27,28,29,Test
30,31,32,33,34,35,36,37,38,39,Test
40,41,42,43,44,45,46,47,48,49,Test
50,51,52,53,54,55,56,57,58,59,Test
60,61,62,63,64,65,66,67,68,69,Test
70,71,72,73,74,75,76,77,78,79,Test
80,81,82,83,84,85,86,87,88,89,Test
90,91,92,93,94,95,96,97,98,99,Test

請注意,這里我不是在等待 1000 毫秒,而是在等待主線程從System.out.print()傳遞 10 次。 這向您保證,如果某事減慢1200ms等 10 次的總和不是1000ms ,而是例如 1200 毫秒,您的第二個線程仍將等待被調用 10 次之前打印Test

免責聲明:我認為上述解決方案是矯枉過正。 如果它是用於概念演示,那么很好,但如果它是真正的生產代碼,我會與main的所有者討論以適應實現而不必覆蓋標准PrintStream

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM