简体   繁体   English

Java Volatile,同步,原子示例

[英]Java Volatile ,synchronization,atomic example

Hi I am reading java concurrency in practice and I read interesting statement states that 嗨,我正在实践中阅读Java并发性,并且阅读了有趣的声明,指出

Locking can guarantee both visibility and atomicity; 锁定可以保证可见性和原子性。 volatile variables can only guarantee visibility. volatile变量只能保证可见性。

Can any one please explain that if declaring a variable as volatile all other reading threads getting updated values so why do i care about the atomicity in statement like: counter = counter + 1 ; 谁能解释一下,如果将一个变量声明为volatile,所有其他读取线程都将获得更新的值,那么为什么我要关心语句中的原子性,如: counter = counter + 1 ;

Thanks in advance. 提前致谢。

The effect of the volatile keyword is approximately that each individual read or write operation on that variable is atomic. volatile关键字的影响大约是该变量上的每个读写操作都是原子的。

Notably, however, an operation that requires more than one read/write -- such as i++, which is equivalent to i = i + 1, which does one read and one write -- is not atomic, since another thread may write to i between the read and the write. 但是,值得注意的是,需要多个读/写操作(例如,i ++相当于i = i + 1,可以进行一次读和一次写操作)不是原子操作,因为另一个线程可能会向i写入数据。在读取和写入之间。

The Atomic classes, like AtomicInteger and AtomicReference, provide a wider variety of operations atomically, specifically including increment for AtomicInteger. 像AtomicInteger和AtomicReference这样的Atomic类在原子上提供了各种各样的操作,特别是包括AtomicInteger的增量。

That's why you need to care about atomicity in statements like counter = counter + 1 这就是为什么您需要关心诸如counter = counter + 1之类的语句中的原子性的原因

Please check this post Volatile Vs Atomic 请检查此帖子挥发性与原子性

Here's a self-contained example executable application that demonstrates that volatile on its own is not enough. 这是一个自包含的示例可执行应用程序,演示了仅凭volatile是不够的。 Four threads increment a counter 10,000 times each, so you'd expect the counter to be 40,000 at the end. 四个线程将每个计数器递增10,000次,因此您希望计数器最后为40,000。 It uses a primitive int variable and an AtomicInt, and tries the exercise 5 times each. 它使用原始的int变量和AtomicInt,并分别尝试5次。

import java.util.Collections;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

class AtomicDemo {
    interface Demo extends Callable<Void> {
        int getCounter();
    }

    static class UsePrimitive implements Demo {
        private volatile int counter = 0;

        public Void call() throws Exception {
            for (int i = 1; i <= 10000; ++i) {
                ++counter;
            }
            return null;
        }

        public int getCounter() {
            return counter;
        }
    }

    static class UseAtomic implements Demo {
        final AtomicInteger counter = new AtomicInteger(0);

        public Void call() throws Exception {
            for (int i = 1; i <= 10000; ++i) {
                counter.incrementAndGet();
                System.out.print("");
            }
            return null;
        }

        public int getCounter() {
            return counter.get();
        }
    }

    public static void main(String[] args) throws Exception {
        ExecutorService exec = Executors.newFixedThreadPool(4);
        for (int i = 1; i <= 5; ++i) {
            Demo demo = new UsePrimitive();
            exec.invokeAll(Collections.nCopies(4, demo));
            System.out.println("Count to 40000 using primitive, attempt number " + i + ": " + demo.getCounter());
        }
        for (int i = 1; i <= 5; ++i) {
            Demo demo = new UseAtomic();
            exec.invokeAll(Collections.nCopies(4, demo));
            System.out.println("Count to 40000 using atomic, attempt number " + i + ": " + demo.getCounter());
        }
        exec.shutdownNow();
    }
}

Typical output: 典型输出:

Count to 40000 using primitive, attempt number 1: 39711
Count to 40000 using primitive, attempt number 2: 39686
Count to 40000 using primitive, attempt number 3: 39972
Count to 40000 using primitive, attempt number 4: 39840
Count to 40000 using primitive, attempt number 5: 39865
Count to 40000 using atomic, attempt number 1: 40000
Count to 40000 using atomic, attempt number 2: 40000
Count to 40000 using atomic, attempt number 3: 40000
Count to 40000 using atomic, attempt number 4: 40000
Count to 40000 using atomic, attempt number 5: 40000

You see, only with AtomicInt do you always get the expected results. 您会看到,只有使用AtomicInt才能始终获得预期的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM