【问题标题】:Multiple threads and AtomicInteger多线程和 AtomicInteger
【发布时间】:2017-08-23 05:26:43
【问题描述】:

我从一个关于原子的教程中获取了这段代码,它说:-

“通过使用 AtomicInteger 作为 Integer 的替代品,我们能够在线程安全的庄园中同时递增数字,而无需同步对变量的访问。方法 incrementAndGet() 是一个原子操作,因此我们可以安全地调用它来自多个线程的方法。”

它说这将返回正确的结果,1000 但是没有一个实例达到 1000,它们通常要少得多,例如

test1 result = 532
test2 result = 128

怎么了?

public class AtomicsTest {

    public static void main(String... args){

        AtomicsTest test = new AtomicsTest();        
        test.test1();        
        test.test2();                             
    }

    public void test1() {
        AtomicInteger atomicInt = new AtomicInteger(0);

        ExecutorService executor = Executors.newSingleThreadExecutor();                
        IntStream.range(0,1000).forEach(i->executor.submit( atomicInt::incrementAndGet ));
        System.out.println("test1 result = "+ atomicInt.get());
        executor.shutdown();
    }

    public void test2() {

        AtomicInteger atomicInt = new AtomicInteger(0);

        ExecutorService executor = Executors.newFixedThreadPool(2);            
        IntStream.range(0,1000).forEach(i->executor.submit( atomicInt::incrementAndGet ));
        System.out.println("test2 result = " + atomicInt.get());        
        executor.shutdown();           
    }    
}

【问题讨论】:

  • 除了提供的答案之外,您的示例并未真正测试原子变量的同步。您正在使用单线程执行程序来增加变量,因此即使使用非原子变量,您也会一次增加一个并得到 1000,因为在任何时候只有 1 个线程访问该变量。跨度>
  • @pandaadb 他的第一次测试可能是真的,但不是第二次。我没有立即发现它,但唯一的区别是执行者。
  • @Michael 你是绝对正确的。我忽略了第二个,但看到了第一个 :) 我认为值得指出

标签: java multithreading java-threads atomicinteger


【解决方案1】:

您的问题是您在提交线程后立即打印该值,尽管并非所有线程都必须完成。

public void test1() {
    AtomicInteger atomicInt = new AtomicInteger(0);

    ExecutorService executor = Executors.newSingleThreadExecutor();                
    IntStream.range(0,1000).forEach(i->executor.submit( atomicInt::incrementAndGet ));

    // All threads submitted (not necessarily finished)

    System.out.println("test1 result = "+ atomicInt.get());

    executor.shutdown();

    // Threads are still not necessarily done
}

如果您在打印值之前明确等待执行器服务完成,您应该会看到您期望的结果:

public void test1() {
    try {
        AtomicInteger atomicInt = new AtomicInteger(0);

        ExecutorService executor = Executors.newSingleThreadExecutor();
        IntStream.range(0,1000).forEach(i->executor.submit( atomicInt::incrementAndGet ));

        executor.shutdown();
        // Wait a maximum of ~a million billion years
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.HOURS);

        System.out.println("test1 result = "+ atomicInt.get());
    }
    catch (InterruptedException ex)
    {
        // Oh no!
    }
}

【讨论】:

  • 我倾向于等待执行器 Long.MAX_VALUE 作为更好的模式。
  • 好点。我已经编辑了它。我喜欢它可能要等待一百万年的想法。
猜你喜欢
  • 2017-04-14
  • 2021-08-25
  • 1970-01-01
  • 2016-04-20
  • 1970-01-01
  • 2019-10-06
  • 1970-01-01
  • 2017-08-26
  • 1970-01-01
相关资源
最近更新 更多