ExecutorService具有AtomicInteger,并已同步给出不同的结果

问题描述 投票:1回答:2

以下为代码-AtomicInteger

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class ExecutorExample1 {
    public static void main(String[] args) {
        ExecutorService executorService= Executors.newFixedThreadPool(2);
        executorService.execute(new MyTask());
        executorService.execute(new MyTask());
        executorService.execute(new MyTask());
        executorService.shutdown();
    }
}

class MyTask implements Runnable{
    private static AtomicInteger count = new AtomicInteger(0);
    @Override
    public void run() {
        try {
            count.addAndGet(1);
            task();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void task()throws InterruptedException{
        System.out.println(count + " Enterd Run of: " + Thread.currentThread().getName());
        Thread.sleep(5000);
        System.out.println(count + " Executing: " + Thread.currentThread().getName());
        Thread.sleep(5000);
        System.out.println(count + " Completed Executing: " + Thread.currentThread().getName());
    }
}

以上代码的输出:

2输入运行方式:pool-1-thread-12输入运行方式:pool-1-thread-22执行中:pool-1-thread-22执行中:pool-1-thread-12完成的执行:pool-1-thread-12完成的执行:pool-1-thread-23输入运行方式:pool-1-thread-13执行中:pool-1-thread-13完成的执行:pool-1-thread-1

同一代码用int和同步块替换AtomicInteger

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class ExecutorExample1 {
    public static void main(String[] args) {
        ExecutorService executorService= Executors.newFixedThreadPool(2);
        executorService.execute(new MyTask());
        executorService.execute(new MyTask());
        executorService.execute(new MyTask());
        executorService.shutdown();
    }
}

class MyTask implements Runnable{
    //private static AtomicInteger count = new AtomicInteger(0);
    private static int count = 0;
    @Override
    public void run() {
        try {
            //count.addAndGet(1);
            synchronized (MyTask.class){
                count+=1;
            }
            task();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void task()throws InterruptedException{
        System.out.println(count + " Enterd Run of: " + Thread.currentThread().getName());
        Thread.sleep(5000);
        System.out.println(count + " Executing: " + Thread.currentThread().getName());
        Thread.sleep(5000);
        System.out.println(count + " Completed Executing: " + Thread.currentThread().getName());
    }
}

同步块代码的输出

2输入运行方式:pool-1-thread-21输入运行方式:pool-1-thread-12执行中:pool-1-thread-22执行中:pool-1-thread-12完成的执行:pool-1-thread-22完成的执行:pool-1-thread-13输入运行方式:pool-1-thread-23执行中:pool-1-thread-23完成的执行:pool-1-thread-2

问题?

  1. 为什么输出有差异?
  2. 为什么原子整数增加到2而不是1。
  3. 我如何使用atomicinteger实现同步输出。
  4. 使用挥发性和原子性有什么好处或使用?
java multithreading concurrency executorservice compare-and-swap
2个回答
0
投票

AtomicInteger使用引擎盖下的volatile字段。这是为了确保所有读取器(其他线程)使用最新的值。在第二种情况下使用简单的int时,您的字段不是volatile,因此您看到的1来自陈旧的值。

通过使用volatile关键字,您应该可以获得相似的结果。

另一种方法是使用门确保继续前进之前满足条件。例如,可以使用CountDownLatch来实现(还有其他方法):https://www.baeldung.com/java-countdown-latch


0
投票

+ =运算符不是原子的,请参见Is the += operator thread-safe in Java?

所以在这里,挥发性绝对不够好。

您可以使用同步,但必须将其用于读取和写入。

© www.soinside.com 2019 - 2024. All rights reserved.