开发者

Java volatile variable question

Reading this DZone article about Java concurrency I was wondering if the following code:


    private volatile List list;
    private final Lock lock = new ReentrantLock();

    public void update(List newList) {
        ImmutableList l = new ImmutableList().addAll(newList);
        lock.lock();
        list = l;
        lock.unlock();
    }

    public List get() {
        return list;
    }

is equivalent to:


    private volatile List list;

    public void update(List newList) {
        ImmutableList l = new ImmutableList().addAll(newList); 
        list = l;
    }

    public List get() {
        return list;
    }

The try { } finally { } block was omitted for brevity. I assume the ImmutableList class to be a truly immutable data structure that holds its own data, such as the one p开发者_如何学Crovided in the google-collections library. Since the list variable is volatile and basically what's going on is a copy-on-the-fly, isn't it safe to just skip on using locks?


In this very specific example, I think you would be OK with no locking on the variable reassignment.

In general, I think you are better off using an AtomicReference instead of a volatile variable as the memory consistency effects are the same and the intent is much clearer.


Yes, both of those code samples behave the same way in a concurrent environment. Volatile fields are never cached thread-locally, so after one thread calls update(), which replaces the list with a new list, then get() on all other threads will return the new list.

But if you have code which uses it like this:

list = get()
list = list.add(something) // returns a new immutable list with the new content
update(list)

then it won't work as expected on either of those code examples (if two threads do that in parallel, then the changes made by one of them may be overwritten by the other). But if only one thread is updating the list, or the new value does not depend on the old value, then no problem.


After re-reading this yes they are equivalent.


If we are talking about timing and memory visibility. A volatile read is very close to the time it takes to do a normal read. So if you are doing get() alot then there is little difference. The time it takes to do a volatile write is about 1/3 time to acquire and release a lock. So your second suggestion is a bit faster.

The memory visibility as most people suggested is equivalent, that is any read before the lock acquisition happens before any write after the lock acquisition similar to any read before a volatile read happens before any subsequent write


The following criteria must be met for volatile variables to provide the desired thread-safety:

  1. Writes to the variable do not depend on its current value.
  2. The variable does not participate in invariants with other variables.

Since both are met here - code is thread-safety


I think the default synchronization behavior of volatile doesn't guarantee the ReentrantLock behavior, so it might help with performance. Otherwise, I think it's fine.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜