Uses of volatile without synchronization

后端 未结 3 649
长情又很酷
长情又很酷 2021-01-11 14:15

Knowing that

Reads and writes are atomic for all variables declared volatile

Question1: Can this be understood

相关标签:
3条回答
  • 2021-01-11 14:46

    As a quickly testable example that may illustrate the previous answers, this yields always a final count of 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();
            }
        }
    }
    
    
    }
    
    0 讨论(0)
  • 2021-01-11 15:00

    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. 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.

    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:

    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.

    0 讨论(0)
  • 2021-01-11 15:01

    x++; operation is atomic?

    No. This reduces to 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.

    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)?

    Well, there are all kinds of approaches to concurrency that don't use 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.

    0 讨论(0)
提交回复
热议问题