by BehindJava

What are the most frequent concurrency issues encounter in Java

Home » java » What are the most frequent concurrency issues encounter in Java

In this tutorial we are to learn about the most frequently occured concurrency issues encountered in Java.

The most common concurrency problem I’ve seen, is not realizing that a field written by one thread is not guaranteed to be seen by a different thread. A common application of this:

class MyThread extends Thread {
  private boolean stop = false;

  public void run() {
    while(!stop) {
      doSomeWork();
    }
  }

  public void setStop() {
    this.stop = true;
  }
}

As long as stop is not volatile or setStop and run are not synchronized this is not guaranteed to work. This mistake is especially devilish as in 99.999% it won’t matter in practice as the reader thread will eventually see the change - but we don’t know how soon he saw it.

It can be easy to think synchronized collections grant you more protection than they actually do, and forget to hold the lock between calls. I have seen this mistake a few times:

 List<String> l = Collections.synchronizedList(new ArrayList<String>());
 String[] s = l.toArray(new String[l.size()]);

For example, in the second line above, the toArray() and size() methods are both thread safe in their own right, but the size() is evaluated separately from the toArray(), and the lock on the List is not held between these two calls.

If you run this code with another thread concurrently removing items from the list, sooner or later you will end up with a new String[] returned which is larger than required to hold all the elements in the list, and has null values in the tail. It is easy to think that because the two method calls to the List occur in a single line of code this is somehow an atomic operation, but it is not.

Concurrency problem ever occurred when two different open source libraries did something like this:

private static final String LOCK = "LOCK";  // use matching strings 
                                            // in two different libraries

public doSomestuff() {
   synchronized(LOCK) {
       this.work();
   }
}

At first glance, this looks like a pretty trivial synchronization example. However; because Strings are interned in Java, the literal string “LOCK” turns out to be the same instance of java.lang.String (even though they are declared completely disparately from each other.) The result is obviously bad.