2

我试图将循环的工作分成两个线程。

我正在使用ExecutorService创建第二个线程,同时将主线程用作另一个线程。

我正在使用计数器在达到某个值时停止循环,但是我无法在这两个线程之间同步计数器,并且循环正在运行一个额外的时间。

另外,我在主线程中使用 while 循环来了解所需的计数何时达到打印结束时间,这也不起作用。

ExecutorService executorService = Executors.newFixedThreadPool(1);
    
    Clock clock = new Clock();

    int count = 5;
    AtomicInteger c = new AtomicInteger(1); 
    clock.start();
    
    executorService.execute(()->{
        while (c.get() <= count) {
            
            System.out.println("LOOP ONE" + "----PRINT_ME");
            c.incrementAndGet();
        }
    });
    
    while (c.get() <= count) {
        
        System.out.println("LOOP TWO" + "----PRINT_ME");
        c.incrementAndGet();
    }
    
    while(true) {
        if(c.get() == count) {
            System.out.println("STOPPED");
            clock.stop();
            break;
        }
    }

输出 -

Clock started at -- 2020-07-25T12:32:59.267
LOOP TWO----PRINT_ME
LOOP TWO----PRINT_ME
LOOP TWO----PRINT_ME
LOOP TWO----PRINT_ME
LOOP TWO----PRINT_ME
LOOP ONE----PRINT_ME

在上面的代码中 PRINT_ME 应该只打印 5 次(int count = 5;),但打印了 6 次(额外打印一次)。

我不确定这里发生了什么以及我们如何在两个线程之间共享一个计数。

PSI:如果我添加 Thread.sleep(2000); 在两个循环中

executorService.execute(()->{
        while (c.get() <= count) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("LOOP ONE" + "----PRINT_ME");
            c.incrementAndGet();
        }
    });
    
    while (c.get() <= count) {
        
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("LOOP TWO" + "----PRINT_ME");
        c.incrementAndGet();
    }

输出是:

Clock started at -- 2020-07-25T12:54:15.596
LOOP TWO----PRINT_ME
LOOP ONE----PRINT_ME
LOOP TWO----PRINT_ME
LOOP ONE----PRINT_ME
LOOP TWO----PRINT_ME
LOOP ONE----PRINT_ME
4

1 回答 1

3

问题是您首先轮询计数器,执行一个操作,然后增加计数器,表明工作已经完成。

这会创建一个窗口,两个线程可以同时在其中完成工作,并在完成后执行增量,但为时已晚。

为了更容易可视化,让我们假设所需的计数是 1,并且有两个线程在争夺要执行的任务。在您的实现中,两个线程将首先检查c.get() <= count两者都为,然后执行导致您描述的问题的任务。

为了防止这种情况,线程需要先声明一个“空闲槽”,然后才执行任务。这可以通过在作业开始之前递增计数器来执行,然后在开始每个作业之前验证最大计数条件:

    int count = 5;
    AtomicInteger c = new AtomicInteger(0);

    executorService.execute(()->{
        while (c.incrementAndGet() <= count) {
            // ...
    });

    while (c.incrementAndGet() <= count) {
            // ..
    }
于 2020-07-25T07:47:03.873 回答