Вопрос

I read several posts about concurrency problems but I'm still unsure about something. Can I say that when using synchronized, I get volatile functionality for free, because when the lock on an object will be released, the next thread always reads the modified object. With volatile, the value of an object is immediately reflected to other threads. But when I use synchronized, there is no possibility to immediately reflect it due to the lock on the object. When the lock is released, only then another thread may access it. So I don't have to care about reflecting the value immediately to other threads. Do I understand this right?

[UPDATE]
Example prints always 1 2 3 4 5 6 7 8 9 without volatile.

package main;

public class Counter
{
    public static long count = 0;
}

public class UseCounter implements Runnable
{
    public void increment()
    {
        synchronized (this)
        {       
            Counter.count++;
            System.out.print(Counter.count + " ");
        }
    }

    @Override
    public void run()
    {
        increment();
        increment();
        increment();
    }
}

public class DataRace
{
    public static void main(String args[])
    {
        UseCounter c = new UseCounter();

        Thread t1 = new Thread(c);
        Thread t2 = new Thread(c);
        Thread t3 = new Thread(c);

        t1.start();
        t2.start();
        t3.start();
    }
}
Это было полезно?

Решение

No, a volatile access is not implied by synchronized access according the the Java Memory Model (although on particular implementations, it may be, but you should not depend on that)

Java Language Specification 17.4.4 (on the Java Memory Model):

Synchronization actions induce the synchronized-with relation on actions, defined as follows:

  • An unlock action on monitor m synchronizes-with all subsequent lock actions on m (where "subsequent" is defined according to the synchronization order).

  • A write to a volatile variable v (§8.3.1.4) synchronizes-with all subsequent reads of v by any thread (where "subsequent" is defined according to the synchronization order).

volatile operates on a variable and synchronized operates on the monitor (the 'lock') of an object.

If one Thread A has just exited a synchronized block on object O, and another Thread B has just read a volatile variable (instance field) V on object O, then there is still not a synchronized-with relation between the two threads. There is no guarantee that Thread A will see any data modifications done by Thread B or vice versa, until Thread B also synchronized on object O, or until Thread A also accessed volatile field V on object O.

Другие советы

Having a volatile variable isn't the same as synchronized access. When you mark a variable as volatile, Thread objects accessing the object will not keep a local cache and there will only ever be one "copy". If you combine the two (synchronized and volatile) then it will always be the updated version, and you won't have conflicting access of it.

Your code is guaranteed to print 1 2 3 4 5 6 7 8 9. The reason is that if you have a sequence such as

  1. Thread t1 writes to Counter.count
  2. Thread t1 unlocks object c
  3. Thread t2 locks object c
  4. Thread t2 reads Counter.count

then it is guaranteed that the read at step 4 sees the write at step 1.

This is not the same as volatile because it is not guaranteed that the write is reflected back to memory immediately, rather it is only guaranteed that the write in step 1 is visible to t2 at the end of step 3.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top