繁体   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