Concurrency, BlockingQueues (Java 7) - 1

"Hi, Amigo!"

"Hi, Kim!"

"Today, I'm going to tell you about concurrency."

"Concurrency is a Java class library that includes special classes that have been optimized for work from multiple threads. This is a very interesting and extensive topic. But today we're just going to get an introduction. The package is called java.util.concurrent package. I'll tell you about a couple of interesting classes."

"Atomic types."

"You already know that even count++ is not a thread-safe operation. When a variable is incremented by 1, three operations actually take place. As a result, there may be a conflict when the variable is changed."

"Yeah, Ellie told me not long ago:"

Thread 1 Thread 2 Result
register1 = count;
register1++;
count = register1;
register2 = count;
register2++;
count = register2;
register1 = count;
register2 = count;
register2++;
count = register2;
register1++;
count = register1;

"Exactly. Then Java added data types to perform these operations as one, i.e. atomically (an atom is indivisible)."

"For example, Java has AtomicInteger, AtomicBoolean, AtomicDouble, etc."

"Suppose we need to make a «counter» class:"

Example
class Counter
{
 private int c = 0;

 public void increment()
 {
  c++;
 }

 public void decrement()
 {
  c--;
 }

 public int value()
 {
  return c;
 }
}

"How would you make objects of this class thread-safe?"

"Well, I would make all the methods synchronized and be done with it:"

Example
class synchronized Counter
{
 private int c = 0;

 public synchronized void increment()
 {
  c++;
 }

 public synchronized void decrement()
 {
  c--;
 }

 public synchronized int value()
 {
  return c;
 }
}

"Good work. But, what would it look like if we used atomic types:"

Example
class AtomicCounter
{
 private AtomicInteger c = new AtomicInteger(0);

 public void increment()
 {
  c.incrementAndGet();
 }

 public void decrement()
 {
  c.decrementAndGet();
 }

 public int value()
 {
  return c.get();
 }
}

"Your class and my class both work the same way, but the class with an AtomicInteger works faster."

"Well, is it a small difference?"

"Yes. Based on my experience, I always recommend leading with synchronized. Only when all the application code has been written and the optimization process has begun should you start rewriting the code to use the atomic types. But in any case, I wanted you to know that such types exist. Even if you don't actively use them, there's always a chance you'll run into code where they are used."

"I agree. That makes sense."

"By the way, did you notice that the atomic types are not immutable? In contrast to the standard Integer class, AtomicInteger contains methods for changing its internal state."

"Got it. Just like String and StringBuffer."

"Yes, something like that."

"Thread-safe collections."

"As as example of such a collection, may I present ConcurrentHashMap. How would you make HashMap thread-safe?"

"Make all of its methods synchronized?"

"Sure, but now imagine that you have one such SynchronizedHashMap, and dozens of threads accessing it. And a hundred times a second a new entry is added to the map, and in the process the entire object is locked for reading and writing."

"Well, this is the standard approach. What can you do?"

"Java's creators came up with a few cool things."

"First, they store data in a ConcurrentHashMap in a single block, but divide it into parts called 'buckets'. And when someone changes data in a ConcurrentHashMap, then we only lock the bucket being accessed, rather than the entire object. In other words, many threads can change the object simultaneously."

"Second, do you remember that you can't iterate over the elements of the list/map and change the list at the same time? Such code will throw an exception:"

Don't iterate over the elements of a collection in a loop and simultaneously change it
HashMap<String, Integer> map = new HashMap<String, Integer>();

for (String key: map.keySet())
{
 if (map.get(key) == 0)
  map.remove(key);
}

"But in ConcurrentHashMap, you can:"

Don't iterate over the elements of a collection in a loop and simultaneously change it"
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();

for (String key: map.keySet())
{
 if (map.get(key) == 0)
  map.remove(key);
}

"The concurrent package has many advantages. We just need to understand these classes very well in order to use them."

"I see. Thanks, Kim. These are truly interesting classes. I hope that someday I will master them like a virtuoso."