Why ArrayBlockingQueue constructor use ReentrantLock for visibility? - java

The code is from ArrayBlockingQueue,JAVA 8.
The comment says:Lock only for visibility, not mutual exclusion.
final Object[] items;
int putIndex;
int count;
public ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) {
this(capacity, fair);
final ReentrantLock lock = this.lock;
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
int i = 0;
try {
for (E e : c) {
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
I think the lock guarantees the visibility of count&putIndex.
But why dont use volatile?

The lock guarantees the visibility of all writes during: to count, to putIndex, and to the elements of items that it changes.
It doesn't need to guarantee mutual exclusion, as it is in the constructor and since the reference to this hasn't been given to other threads, there is no need for mutual exclusion (but it would guarantee that as well if the reference to this was given out before that point)
The comment is merely saying that the purpose of the lock is the visibility effects.
As to why you can't use volatile:
The methods that retrieve values from the queue, like poll, take and peek do need to lock for mutual exclusion. Making a variable volatile is not necessary; it could have an adverse performance impact.
It would also be hard to get it right because of the ordering: a volatile write happens before (JLS terminology) a volatile read on the same variable. That means that the constructor would have to write to the volatile variable as its last action, while all code that needs to be correctly synchronized needs to read that volatile variable first before doing anything else.
Locks are much easier to reason about and to get the ordering of accesses right, and, in this case - they are required in any case to execute multiple writes as one atomic action.

The lock guarantees all writes will be visible, including writes to the items array. Making the array volatile would not be enough to ensure writes to array elements are visible to all threads.

Related

why ArrayBlockingQueue Constructor need Lock in JDK 8

There is no practical need for a constructor to be synchronized, because it would lock the object under construction, which is normally not made available to other threads until all constructors for the object have completed their work.
above is in https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.8.3
But I found LOCK used in ArrayBlockingQueue's Constructor. Why it is used ?
public ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c) {
this(capacity, fair);
final ReentrantLock lock = this.lock;
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
int i = 0;
try {
for (E e : c) {
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
The comment // Lock only for visibility, not mutual exclusion tells you about it. Depending on the CPU we can have a situation where the constructing thread "leaves" our constructor but the fields are not yet initialized (so in our example thread leaves ArrayBlockingQueue constructor but our count, putIndex, items fields are not yet initialized and some other thread started using offer/add methods). The same lock strategy is used in LinkedBlockingQueue. Also, JVM have capabilities to reorder our bytecode instructions inside our method/constructor. And for last there may be a situation that a thread can obtain a reference before another thread finishes constructing the object.
Here you can read more about it:
Constructor synchronization in Java
And also, there are many blog posts about Memory Visibility.

Volatile and ArrayBlockingQueue and perhaps other concurrent objects

I understand (or at least I think I do;) ) the principle behind volatile keyword.
When looking into ConcurrentHashMap source, you can see that all nodes and values are declared volatile, which makes sense because the value can be written/read from more than one thread:
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
...
}
However, looking into ArrayBlockingQueue source, it's a plain array that is being updated/read from multiple threads:
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0;
count++;
notEmpty.signal();
}
How is it guaranteed that the value inserted into items[putIndex] will be visible from another thread, providing that the element inside the array is not volatile (i know that declaring the array itself doesnt have any effect anyhow on the elements themselves) ?
Couldn't another thread hold a cached copy of the array?
Thanks
Notice that enqueue is private. Look for all calls to it (offer(E), offer(E, long, TimeUnit), put(E)). Notice that every one of those looks like:
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
// Do stuff.
enqueue(e);
} finally {
lock.unlock();
}
}
So you can conclude that every call to enqueue is protected by a lock.lock() ... lock.unlock() so you don't need volatile because lock.lock/unlock are also a memory barrier.
According to my understanding volatile is not needed as all BlockingQueue implementations already have a locking mechanism unlike the ConcurrentHashMap.
If you look at he public methods of the Queue you will find a ReentrantLock that guards for concurrent access.

Are java getters thread-safe?

Is is okay to synchronize all methods which mutate the state of an object, but not synchronize anything which is atomic? In this case, just returning a field?
Consider:
public class A
{
private int a = 5;
private static final Object lock = new Object();
public void incrementA()
{
synchronized(lock)
{
a += 1;
}
}
public int getA()
{
return a;
}
}
I've heard people argue that it's possible for getA() and incrementA() to be called at roughly the same time and have getA() return to wrong thing. However it seems like, in the case that they're called at the same time, even if the getter is synchronized you can get the wrong thing. In fact the "right thing" doesn't even seem defined if these are called concurrently. The big thing for me is that the state remains consistent.
I've also heard talk about JIT optimizations. Given an instance of the above class and the following code(the code would be depending on a to be set in another thread):
while(myA.getA() < 10)
{
//incrementA is not called here
}
it is apparently a legal JIT optimization to change this to:
int temp = myA.getA();
while(temp < 10)
{
//incrementA is not called here
}
which can obviously result in an infinite loop.
Why is this a legal optimization? Would this be illegal if a was volatile?
Update
I did a little bit of testing into this.
public class Test
{
private int a = 5;
private static final Object lock = new Object();
public void incrementA()
{
synchronized(lock)
{
a += 1;
}
}
public int getA()
{
return a;
}
public static void main(String[] args)
{
final Test myA = new Test();
Thread t = new Thread(new Runnable(){
public void run() {
while(true)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
myA.incrementA();
}
}});
t.start();
while(myA.getA() < 15)
{
System.out.println(myA.getA());
}
}
}
Using several different sleep times, this worked even when a is not volatile. This of course isn't conclusive, it still may be legal. Does anyone have some examples that could trigger such JIT behaviour?
Is is okay to synchronize all methods which mutate the state of an object, but not synchronize anything which is atomic? In this case, just returning a field?
Depends on the particulars. It is important to realize that synchronization does two important things. It is not just about atomicity but it is also required because of memory synchronization. If one thread updates the a field, then other threads may not see the update because of memory caching on the local processor. Making the int a field be volatile solves this problem. Making both the get and the set method be synchronized will as well but it is more expensive.
If you want to be able to change and read a from multiple threads, the best mechanism is to use an AtomicInteger.
private AtomicInteger a = new AtomicInteger(5);
public void setA(int a) {
// no need to synchronize because of the magic of the `AtomicInteger` code
this.a.set(a);
}
public int getA() {
// AtomicInteger also takes care of the memory synchronization
return a.get();
}
I've heard people argue that it's possible for getA() and setA() to be called at roughly the same time and have getA() return to wrong thing.
This is true but you can get the wrong value if getA() is called after setA() as well. A bad cache value can stick forever.
which can obviously result in an infinite loop. Why is this a legal optimization?
It is a legal optimization because threads running with their own memory cache asynchronously is one of the important reasons why you see performance improvements with them. If all memory accesses where synchronized with main memory then the per-CPU memory caches would not be used and threaded programs would run a lot slower.
Would this be illegal if a was volatile?
It is not legal if there is some way for a to be altered – by another thread possibly. If a was final then the JIT could make that optimization. If a was volatile or the get method marked as synchronized then it would certainly not be a legal optimization.
It's not thread safe because that getter does not ensure that a thread will see the latest value, as the value may be stale. Having the getter be synchronized ensures that any thread calling the getter will see the latest value instead of a possible stale one.
You basically have two options:
1) Make your int volatile
2) Use an atomic type like AtomicInt
using a normal int without synchronization is not thread safe at all.
Your best solution is to use an AtomicInteger, they were basically designed for exactly this use case.
If this is more of a theoretical "could this be done question", I think something like the following would be safe (but still not perform as well as an AtomicInteger):
public class A
{
private volatile int a = 5;
private static final Object lock = new Object();
public void incrementA()
{
synchronized(lock)
{
final int tmp = a + 1;
a = tmp;
}
}
public int getA()
{
return a;
}
}
The short answer is your example will be thread-safe, if
the variable is declared as volatile, or
the getter is declared as synchronized.
The reason that your example class A is not thread-safe is that one can create a program using it that doesn't have a "well-formed execution" (see JLS 17.4.7).
For instance, consider
// in thread #1
int a1 = A.getA();
Thread.sleep(...);
int a2 = A.getA();
if (a1 == a2) {
System.out.println("no increment");
// in thread #2
A.incrementA();
in the scenario that the increment happens during the sleep.
For this execution to be well-formed, there must be a "happens before" (HB) chain between the assignment to a in incrementA called by thread #2, and the subsequent read of a in getA called by thread #1.
If the two threads synchronize using the same lock object, then there is a HB between one thread releasing the lock and a second thread acquiring the lock. So we get this:
thread #2 acquires lock --HB-->
thread #2 reads a --HB-->
thread #2 writes a --HB-->
thread #2 releases lock --HB-->
thread #1 acquires lock --HB-->
thread #1 reads a
If two threads share a a volatile variable, there is a HB between any write and any subsequent read (without an intervening write). So we typically get this:
thread #2 acquires lock --HB-->
thread #2 reads a --HB-->
thread #2 writes a --HB-->
thread #1 reads a
Note that incrementA needs to be synchronized to avoid race conditions with other threads calling incrementA.
If neither of the above is true, we get this:
thread #2 acquires lock --HB-->
thread #2 reads a --HB-->
thread #2 writes a // No HB!!
thread #1 reads a
Since there is no HB between the write by thread #2 and the subsequent read by thread #1, the JLS does not guarantee that the latter will see the value written by the former.
Note that this is a simplified version of the rules. For the complete version, you need to read all of JLS Chapter 17.

How do I create a Lock (concurrent.locks.Lock) in Android?

This must be really obvious, but I can't spot the answer. I need to put a lock around a variable to ensure that a couple of race-hazard conditions are avoided. From what I can see, a pretty simple solution exists using Lock, according to the android docs:
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
}
finally {
l.unlock();
}
So far, so good. However, I can't make the first line work. It would seem that something like:
Lock l = new Lock();
Might be correct, but eclipse reports, "Cannot instantiate the type Lock" - and no more.
Any suggestions?
If you're very keen on using a Lock, you need to choose a Lock implementation as you cannot instantiate interfaces.
As per the docs
You have 3 choices:
ReentrantLock
Condition This isn't a Lock itself but rather a helper class since Conditions are bound to Locks.
ReadWriteLock
You're probably looking for the ReentrantLock possibly with some Conditions
This means that instead of Lock l = new Lock(); you would do:
ReentrantLock lock = new ReentrantLock();
However, if all you're needing to lock is a small part, a synchronized block/method is cleaner (as suggested by #Leonidos & #assylias).
If you have a method that sets the value, you can do:
public synchronized void setValue (var newValue)
{
value = newValue;
}
or if this is a part of a larger method:
public void doInfinite ()
{
//code
synchronized (this)
{
value = aValue;
}
}
Just because Lock is an interface and can't be instantiated. Use its subclasses.

Synchronization of non-final field

A warning is showing every time I synchronize on a non-final class field. Here is the code:
public class X
{
private Object o;
public void setO(Object o)
{
this.o = o;
}
public void x()
{
synchronized (o) // synchronization on a non-final field
{
}
}
}
so I changed the coding in the following way:
public class X
{
private final Object o;
public X()
{
o = new Object();
}
public void x()
{
synchronized (o)
{
}
}
}
I am not sure the above code is the proper way to synchronize on a non-final class field. How can I synchronize a non final field?
First of all, I encourage you to really try hard to deal with concurrency issues on a higher level of abstraction, i.e. solving it using classes from java.util.concurrent such as ExecutorServices, Callables, Futures etc.
That being said, there's nothing wrong with synchronizing on a non-final field per se. You just need to keep in mind that if the object reference changes, the same section of code may be run in parallel. I.e., if one thread runs the code in the synchronized block and someone calls setO(...), another thread can run the same synchronized block on the same instance concurrently.
Synchronize on the object which you need exclusive access to (or, better yet, an object dedicated to guarding it).
It's really not a good idea - because your synchronized blocks are no longer really synchronized in a consistent way.
Assuming the synchronized blocks are meant to be ensuring that only one thread accesses some shared data at a time, consider:
Thread 1 enters the synchronized block. Yay - it has exclusive access to the shared data...
Thread 2 calls setO()
Thread 3 (or still 2...) enters the synchronized block. Eek! It think it has exclusive access to the shared data, but thread 1 is still furtling with it...
Why would you want this to happen? Maybe there are some very specialized situations where it makes sense... but you'd have to present me with a specific use case (along with ways of mitigating the sort of scenario I've given above) before I'd be happy with it.
I agree with one of John's comment: You must always use a final lock dummy while accessing a non-final variable to prevent inconsistencies in case of the variable's reference changes. So in any cases and as a first rule of thumb:
Rule#1: If a field is non-final, always use a (private) final lock dummy.
Reason #1: You hold the lock and change the variable's reference by yourself. Another thread waiting outside the synchronized lock will be able to enter the guarded block.
Reason #2: You hold the lock and another thread changes the variable's reference. The result is the same: Another thread can enter the guarded block.
But when using a final lock dummy, there is another problem: You might get wrong data, because your non-final object will only be synchronized with RAM when calling synchronize(object). So, as a second rule of thumb:
Rule#2: When locking a non-final object you always need to do both: Using a final lock dummy and the lock of the non-final object for the sake of RAM synchronisation. (The only alternative will be declaring all fields of the object as volatile!)
These locks are also called "nested locks". Note that you must call them always in the same order, otherwise you will get a dead lock:
public class X {
private final LOCK;
private Object o;
public void setO(Object o){
this.o = o;
}
public void x() {
synchronized (LOCK) {
synchronized(o){
//do something with o...
}
}
}
}
As you can see I write the two locks directly on the same line, because they always belong together. Like this, you could even do 10 nesting locks:
synchronized (LOCK1) {
synchronized (LOCK2) {
synchronized (LOCK3) {
synchronized (LOCK4) {
//entering the locked space
}
}
}
}
Note that this code won't break if you just acquire an inner lock like synchronized (LOCK3) by another threads. But it will break if you call in another thread something like this:
synchronized (LOCK4) {
synchronized (LOCK1) { //dead lock!
synchronized (LOCK3) {
synchronized (LOCK2) {
//will never enter here...
}
}
}
}
There is only one workaround around such nested locks while handling non-final fields:
Rule #2 - Alternative: Declare all fields of the object as volatile. (I won't talk here about the disadvantages of doing this, e.g. preventing any storage in x-level caches even for reads, aso.)
So therefore aioobe is quite right: Just use java.util.concurrent. Or begin to understand everything about synchronisation and do it by yourself with nested locks. ;)
For more details why synchronisation on non-final fields breaks, have a look into my test case: https://stackoverflow.com/a/21460055/2012947
And for more details why you need synchronized at all due to RAM and caches have a look here: https://stackoverflow.com/a/21409975/2012947
I'm not really seeing the correct answer here, that is, It's perfectly alright to do it.
I'm not even sure why it's a warning, there is nothing wrong with it. The JVM makes sure that you get some valid object back (or null) when you read a value, and you can synchronize on any object.
If you plan on actually changing the lock while it's in use (as opposed to e.g. changing it from an init method, before you start using it), you have to make the variable that you plan to change volatile. Then all you need to do is to synchronize on both the old and the new object, and you can safely change the value
public volatile Object lock;
...
synchronized (lock) {
synchronized (newObject) {
lock = newObject;
}
}
There. It's not complicated, writing code with locks (mutexes) is actally quite easy. Writing code without them (lock free code) is what's hard.
EDIT: So this solution (as suggested by Jon Skeet) might have an issue with atomicity of implementation of "synchronized(object){}" while object reference is changing. I asked separately and according to Mr. erickson it is not thread safe - see: Is entering synchronized block atomic?. So take it as example how to NOT do it - with links why ;)
See the code how it would work if synchronised() would be atomic:
public class Main {
static class Config{
char a='0';
char b='0';
public void log(){
synchronized(this){
System.out.println(""+a+","+b);
}
}
}
static Config cfg = new Config();
static class Doer extends Thread {
char id;
Doer(char id) {
this.id = id;
}
public void mySleep(long ms){
try{Thread.sleep(ms);}catch(Exception ex){ex.printStackTrace();}
}
public void run() {
System.out.println("Doer "+id+" beg");
if(id == 'X'){
synchronized (cfg){
cfg.a=id;
mySleep(1000);
// do not forget to put synchronize(cfg) over setting new cfg - otherwise following will happend
// here it would be modifying different cfg (cos Y will change it).
// Another problem would be that new cfg would be in parallel modified by Z cos synchronized is applied on new object
cfg.b=id;
}
}
if(id == 'Y'){
mySleep(333);
synchronized(cfg) // comment this and you will see inconsistency in log - if you keep it I think all is ok
{
cfg = new Config(); // introduce new configuration
// be aware - don't expect here to be synchronized on new cfg!
// Z might already get a lock
}
}
if(id == 'Z'){
mySleep(666);
synchronized (cfg){
cfg.a=id;
mySleep(100);
cfg.b=id;
}
}
System.out.println("Doer "+id+" end");
cfg.log();
}
}
public static void main(String[] args) throws InterruptedException {
Doer X = new Doer('X');
Doer Y = new Doer('Y');
Doer Z = new Doer('Z');
X.start();
Y.start();
Z.start();
}
}
AtomicReference suits for your requirement.
From java documentation about atomic package:
A small toolkit of classes that support lock-free thread-safe programming on single variables. In essence, the classes in this package extend the notion of volatile values, fields, and array elements to those that also provide an atomic conditional update operation of the form:
boolean compareAndSet(expectedValue, updateValue);
Sample code:
String initialReference = "value 1";
AtomicReference<String> someRef =
new AtomicReference<String>(initialReference);
String newReference = "value 2";
boolean exchanged = someRef.compareAndSet(initialReference, newReference);
System.out.println("exchanged: " + exchanged);
In above example, you replace String with your own Object
Related SE question:
When to use AtomicReference in Java?
If o never changes for the lifetime of an instance of X, the second version is better style irrespective of whether synchronization is involved.
Now, whether there's anything wrong with the first version is impossible to answer without knowing what else is going on in that class. I would tend to agree with the compiler that it does look error-prone (I won't repeat what the others have said).
Just adding my two cents: I had this warning when I used component that is instantiated through designer, so it's field cannot really be final, because constructor cannot takes parameters. In other words, I had quasi-final field without the final keyword.
I think that's why it is just warning: you are probably doing something wrong, but it might be right as well.

Categories

Resources