Java 这个多线程代码保证总是返回零吗?

Java 这个多线程代码保证总是返回零吗?,java,concurrency,Java,Concurrency,我正在拿一本书做模拟测试,我发现了这个问题: import java.util.concurrent.atomic.AtomicInteger; class AtomicVariableTest { private static AtomicInteger counter = new AtomicInteger(0); static class Decrementer extends Thread { public void run() {

我正在拿一本书做模拟测试,我发现了这个问题:

import java.util.concurrent.atomic.AtomicInteger;

class AtomicVariableTest {

    private static AtomicInteger counter = new AtomicInteger(0);

    static class Decrementer extends Thread {

        public void run() {
            counter.decrementAndGet(); // #1
        }
    }

    static class Incrementer extends Thread {

        public void run() {
            counter.incrementAndGet(); // #2
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            new Incrementer().start();
            new Decrementer().start();
        }
        System.out.println(counter);
    }
}
导入java.util.concurrent.AtomicInteger;
类原子变量测试{
私有静态AtomicInteger计数器=新的AtomicInteger(0);
静态类递减器扩展线程{
公开募捐{
计数器。递减获取();/#1
}
}
静态类递增器扩展线程{
公开募捐{
counter.incrementAndGet();/#2
}
}
公共静态void main(字符串[]args){
对于(int i=0;i<5;i++){
新的递增器().start();
新的减量器().start();
}
系统输出打印项次(计数器);
}
}
答案是:

此程序将始终打印0

但是我认为不能保证线程在打印计数器值时已经完成

我的意思是,大多数时候它都会返回0,但是如果你严格遵守这个理论,就不能保证这一点


我说的对吗?

有保证。而且也不能保证。没有中间立场

在这种情况下,保证结果始终为零。这是因为线程没有连接-甚至可能在打印之前从未实际运行过

例如,在其他排列中,该代码可能执行的顺序是:

counter.decrementAndGet();    // #1
System.out.println(counter);  // Main thread
counter.incrementAndGet();    // #2
// (and so on, at some arbitrary point after the print)
避免这种不希望的交错/执行是在Java中(根据JLS)在“发生在关系之前”下处理的

如果线程被连接(到带有打印的线程),那么将建立之前发生的事件-在本例中,这意味着线程开始并完成运行-并且结果将保证为零

public static void main(String[] args) {
    final List<Thread> threads = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        final new Incrementer i = new Incrementer();
        threads.add(i);
        i.start();
        final new Decrementer d = new Decrementer();
        threads.add(d);
        d.start();
    }
    for (final Thread t : threads) { t.join(); }
    System.out.println(counter);
}
publicstaticvoidmain(字符串[]args){
最终列表线程=新的ArrayList();
对于(int i=0;i<5;i++){
最终新增量器i=新增量器();
添加(i);
i、 start();
最终新减量器d=新减量器();
添加(d);
d、 start();
}
对于(最终线程t:threads){t.join();}
系统输出打印项次(计数器);
}
请参阅众多副本之一:


这就是为什么您使用
ExecutorService
ExecutorCompletionService
并且从不手动处理线程管理,因为否则它极易出错。

当然,我可以尝试数千次而不必幸运!我只是想知道你是否同意我投票结束这个问题,因为你不是在问一个有具体答案的问题,而是在要求讨论。这不是一个论坛,讨论非常离题。这个问题不是要讨论,而是要问一个关于特定代码段如何工作的特定问题。我可以将问题改为“正确答案是什么?”Ritt。。。事实上,我认为这个问题只有一个答案这是一个重复的,即使它现在是正确的,它的措辞非常不清楚,你需要用一个代码示例来说明
.join()
将在何处按描述进行。我修复了它,你可以删除你在我查找它时所做的评论,我也觉得不太对劲。