简体   繁体   English

使用volatile而不同步

[英]Uses of volatile without synchronization

Knowing that 知道

Reads and writes are atomic for all variables declared volatile 对于声明为volatile的所有变量,读取和写入都是原子

Question1: Can this be understood as if 问题1:这可以理解为

private volatile int x = 0;

x++; operation is atomic? 操作是原子的?

And that 然后

Marking variable volatile does not eliminate all need to synchronize atomic actions, because memory consistency errors are still possible. 标记变量volatile并不能消除所有同步原子操作的需要,因为仍然可能存在内存一致性错误。

Question2: I wonder under what circumstances (if any) it is possible to see a variable marked volatile and not see any methods of blocks marked synchronized (that attempt to access/ modify the variable)? 问题2:我想知道在什么情况下(如果有的话)可以看到标记为volatile的变量并且看不到任何标记为synchronized的块的方法(试图访问/修改变量)?

In other words, should all variables that need to be protected from concurrent modification be marked volatile ? 换句话说,是否应将所有需要保护以防止并发修改的变量标记为volatile

The volatile only gives you additional visibility guarantees, atomic writes/reads for longs/doubles (otherwise not guaranteed by the JLS, yes) and some memory order guarantees. volatile只为你提供额外的可见性保证,long / double的原子写入/读取(否则不能由JLS保证,是)和一些内存顺序保证。 No synchronization (it is possible though to build synchronization blocks starting with just volatile - Dekker's algorithm ) So no, it does not help you with x++ - that's still a read, inc and write and needs some form of synchronization. 没有同步(虽然可以构建以volatile开头的同步块 - Dekker的算法 )所以不,它对x++没有帮助 - 它仍然是一个读取,包含和写入,需要某种形式的同步。

One example of volatile is the famous double-checked locking, where we avoid synchronization most of the time because the ordering guarantees are all we need: volatile的一个例子是着名的双重检查锁定,我们大部分时间都避免同步,因为排序保证是我们所需要的:

private volatile Helper helper = null;
public Helper getHelper() {
    if (helper == null) {
        synchronized(this) {
            if (helper == null) {
                helper = new Helper();
            }
        }
    }
    return helper;
}

An example where there's absolutely no synchronization involved, is a simple exit flag, here it's not about ordering guarantees but only about the guaranteed visibility 一个绝对没有涉及同步的例子是一个简单的退出标志,这里不是关于订购保证而是关于保证的可见性

public volatile boolean exit = false;
public void run() {
   while (!exit) doStuff();
   // exit when exit set to true
}

If another thread sets exit = true the other thread doing the while loop is guaranteed to see the update - without volatile it may not. 如果另一个线程设置exit = true那么执行while循环的另一个线程将保证看到更新 - 没有volatile,它可能不会。

x++; X ++; operation is atomic? 操作是原子的?

No. This reduces to x = x + 1 . 不会。这会减少到x = x + 1 The read of x is atomic, and the write to x is atomic, but x = x + 1 as a whole is not atomic. x的读取是原子的,对x的写入是原子的,但x = x + 1整体上不是原子的。

I wonder under what circumstances (if any) it is possible to see a variable marked volatile and not see any methods of blocks marked synchronized (that attempt to access/ modify the variable)? 我想知道在什么情况下(如果有的话)可以看到标记为volatile的变量并且看不到任何标记为synchronized的块的方法(尝试访问/修改变量)?

Well, there are all kinds of approaches to concurrency that don't use synchronized . 好吧,有各种不使用synchronized并发方法。 There's a wide variety of other locking utilities in Java, and lock-free algorithms that still require things like volatile : ConcurrentLinkedQueue is a specific example, though it makes extensive use of "magical" compareAndSet atomics. Java中有各种各样的其他锁定实用程序,而且无锁算法仍然需要像volatile这样的东西: ConcurrentLinkedQueue是一个特定的例子,尽管它广泛使用了“神奇的” compareAndSet原子。

As a quickly testable example that may illustrate the previous answers, this yields always a final count of 8: 作为一个可以快速测试的例子,可以说明以前的答案,这总是最终计数为8:

import java.util.concurrent.atomic.AtomicInteger;


public class ThreadTest_synchronize {

public static void main(String[] args) {

    ThreadTest_synchronize tt = new ThreadTest_synchronize ();
    try {
        tt.go();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

private void go() throws InterruptedException{

    MyRunnable t = new MyRunnable();
    Thread myThread_1 = new Thread( t, "t1");
    Thread myThread_2 = new Thread( t, "t2");
    myThread_1.start();
    myThread_2.start();
    myThread_1.join();
    myThread_2.join();
    System.out.println("Processing count="+t.getCount());       

}

private class MyRunnable implements Runnable{

    private AtomicInteger count=new AtomicInteger(0);

    @Override
    public  void run() {
        for(int i=1; i< 5; i++){
            doSomething(i);
            count.getAndAdd(1);
        }           
    }


    public AtomicInteger getCount() {
        return this.count;
    }


    private void doSomething(int i) {
        try {
            Thread.sleep(i*300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}       

}

while this generally does not: 虽然这通常不会:

public class ThreadTest_volatile {

public static void main(String[] args) {

    ThreadTest_volatile tt = new ThreadTest_volatile ();
    try {
        tt.go();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

private void go() throws InterruptedException{

    MyRunnable t = new MyRunnable();
    Thread myThread_1 = new Thread( t, "t1");
    Thread myThread_2 = new Thread( t, "t2");
    myThread_1.start();
    myThread_2.start();
    myThread_1.join();
    myThread_2.join();
    System.out.println("Processing count="+t.getCount());       

}

private class MyRunnable implements Runnable{

    private volatile int count = 0;


    @Override
    public  void run() {
        for(int i=1; i< 5; i++){
            doSomething(i);
            count++;
        }

    }

    private  int add(int count){
        return ++count;
    }


    public int getCount(){
        return count;
    }

    private void doSomething(int i) {

        try {
            Thread.sleep(i*300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


}

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

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