Java Concurrency
Gotchas
Alex Miller
Questions to answer
• What are common concurrency problems?
• Why are they problems?
• How do I detect these problems?
• H...
Areas of Focus
• Shared Data
• Coordination
• Performance
Areas of Focus
• Shared Data
• Coordination
• Performance

{

• Locking
• Visibility
• Atomicity
• Safe Publication
Unprotected Field
Access
A

What happens if we modify data
without locking?
Writer

Readers

Shared state
Locking
A
Shared Mutable Statics
public class MutableStatics {

FORMAT is mutable

private static final DateFormat FORMAT =
DateForm...
Shared mutable statics instance per call
public class MutableStatics {
public static Date parse(String str)
throws ParseEx...
Shared mutable statics ThreadLocal
public class MutableStatics {
private static final ThreadLocal<DateFormat> FORMAT
= new...
Common JDK Examples
Danger!

Safe

• DateFormat
• Calendar
• Matcher

• Random
• Pattern
Synchronization
private int myField;
synchronized( What goes here? ) {
myField = 0;
}
DO NOT:
synchronize on null
MyObject obj = null;
synchronized( obj ) { NullPointerException!
// work
}
DO NOT:
change instance
MyObject obj = new MyObject();
synchronized( obj ) {
obj = new MyObject();
no longer synchronizing...
DO NOT:
synch on string literals
private static final String LOCK = “LOCK”;
synchronized( LOCK ) {
// work
What is the sco...
DO NOT:
synch on autoboxed vals
private static final Integer LOCK = 0;
synchronized( LOCK ) { What is the scope of LOCK?
/...
DO NOT:
synch on ReentrantLock
Lock lock = new ReentrantLock();
synchronized(lock) {
// ...
Probably not what you meant he...
What should I lock on?
// The field you’re protecting
private final Map map = ...
synchronized(map) {
// ...access map
}

...
Visibility
Visibility problems
int x = 5;
Thread 1:
if(x == 5) {
x = 10;
}
Thread 2:
System.out.println(x);
Visibility problems
volatile int x = 5;
Thread 1:
if(x == 5) {
x = 10;
}
Thread 2:
System.out.println(x);
Inconsistent
Synchronization
public class SomeData {
private final Map data = new HashMap();
public void set(String key, S...
Double-checked locking
public class Singleton {
private static Singleton instance;

}

public static Singleton getInstance...
Double-checked locking
public class Singleton {
private static Singleton instance;

}

public static Singleton getInstance...
Double-checked locking
- volatile
public class Singleton {
private static volatile Singleton instance;

}

public static S...
Double-checked locking
- initialize on demand
public class Singleton {
private static class SingletonHolder {
private stat...
volatile arrays
public final class VolatileArray {
private volatile boolean[] vals;
public void flip(int i) {
Is the value...
Atomicity
Volatile counter
public class Counter {
private volatile int count;

}

public int next() {
return count++;
}

Looks atomi...
AtomicInteger counter
public class Counter {
private AtomicInteger count =
new AtomicInteger();

}

public int next() {
re...
Composing atomic actions
public Object putIfAbsent(
Hashtable table, Object key, Object value) {
Hashtable is
thread-safe
...
Composing atomic actions
public Object putIfAbsent(
Hashtable table, Object key, Object value) {
Hashtable is
thread-safe
...
Participate in lock
public Object putIfAbsent(
Hashtable table, Object key, Object value) {
Hashtable is
thread-safe

}

s...
Encapsulated compound
actions
public Object putIfAbsent(
ConcurrentHashMap table, Object key, Object value) {
}

return ta...
Assignment of
64 bit values
public class LongAssignment {
private long x;
public void setLong(long val) {
x = val;
Looks a...
Assignment of
64 bit values - volatile
public class LongAssignment {
private volatile long x;
public void setLong(long val...
Safe publication
Listener in constructor
public interface DispatchListener {
void newFare(Customer customer);
}
public class Taxi
implement...
Starting thread
in constructor
public class Cache {
private final Thread cleanerThread;
public Cache() {
cleanerThread = n...
Static factory method
public class Cache {
// ...

}

public static Cache newCache() {
Cache cache = new Cache();
cache.st...
Areas of Focus
• Shared Data
• Coordination
• Performance

{

• Threads
• Wait/notify
Threads
• THOU SHALT NOT:
• call Thread.stop()
• call Thread.suspend() or Thread.resume()

All monitors unlocked by ThreadDeath

C...
wait/notify
// Thread 1
synchronized(lock) { You must synchronize.
while(! someCondition()) { Always wait in a loop.
lock....
Condition is similar
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition(...
Areas of Focus
• Shared Data
• Coordination
• Performance

{

• Deadlock
• Spin wait
• Thread contention
Deadlock
// Thread 1
synchronized(lock1) {
synchronized(lock2) {
// stuff
}
}
// Thread 2
synchronized(lock2) {
synchroniz...
Deadlock avoidance
• Lock splitting
• Lock ordering
• Lock timeout
• tryLock
Spin wait
// Not efficient
private volatile boolean flag = false;
public void waitTillChange() {
while(! flag) {
Spin on fl...
Replace with Condition
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newConditio...
CountDownLatch
private final CountDownLatch latch =
new CountDownLatch(1);
public void waitTillChange() {
latch.await();
}...
Lock contention
x

Hash f(x)

Bucket 0

Bucket 1

Bucket 2

Bucket 3
Lock striping
x

Hash g(x)

Hash f(x)

Bucket 0

Bucket 1

Hash f(x)

Bucket 0

Bucket 1
Final Exam
public class StatisticsImpl implements Statistics,
StatisticsImplementor {
private long queryExecutionCount;
pu...
Final Exam
public class StatisticsImpl implements Statistics,
StatisticsImplementor {
private long queryExecutionCount;
Si...
Thanks...
Twitter
Blog
Concurrency
links

http://twitter.com/puredanger
http://tech.puredanger.com
http://concurrency.tumb...
Concurrency gotchas
Upcoming SlideShare
Loading in...5
×

Concurrency gotchas

150
-1

Published on

Published in: Education, Technology, Business
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
150
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
8
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Concurrency gotchas

  1. 1. Java Concurrency Gotchas Alex Miller
  2. 2. Questions to answer • What are common concurrency problems? • Why are they problems? • How do I detect these problems? • How to I correct these problems?
  3. 3. Areas of Focus • Shared Data • Coordination • Performance
  4. 4. Areas of Focus • Shared Data • Coordination • Performance { • Locking • Visibility • Atomicity • Safe Publication
  5. 5. Unprotected Field Access A What happens if we modify data without locking?
  6. 6. Writer Readers Shared state
  7. 7. Locking A
  8. 8. Shared Mutable Statics public class MutableStatics { FORMAT is mutable private static final DateFormat FORMAT = DateFormat.getDateInstance(DateFormat.MEDIUM); public static Date parse(String str) throws ParseException { return FORMAT.parse(str); } ...and this mutates it outside synchronization } public static void main(String arg[]) throws Exception { MutableStatics.parse(“Jan 1, 2000”); }
  9. 9. Shared mutable statics instance per call public class MutableStatics { public static Date parse(String str) throws ParseException { DateFormat format = DateFormat.getDateInstance(DateFormat.MEDIUM); return format.parse(str); } } public static void main(String arg[]) throws Exception { MutableStatics.parse(“Jan 1, 2000”); }
  10. 10. Shared mutable statics ThreadLocal public class MutableStatics { private static final ThreadLocal<DateFormat> FORMAT = new ThreadLocal<DateFormat>() { @Override protected DateFormat initialValue() { return DateFormat.getDateInstance( DateFormat.MEDIUM); } }; } public static Date parse(String str) throws ParseException { return FORMAT.get().parse(str); }
  11. 11. Common JDK Examples Danger! Safe • DateFormat • Calendar • Matcher • Random • Pattern
  12. 12. Synchronization private int myField; synchronized( What goes here? ) { myField = 0; }
  13. 13. DO NOT: synchronize on null MyObject obj = null; synchronized( obj ) { NullPointerException! // work }
  14. 14. DO NOT: change instance MyObject obj = new MyObject(); synchronized( obj ) { obj = new MyObject(); no longer synchronizing on same object! }
  15. 15. DO NOT: synch on string literals private static final String LOCK = “LOCK”; synchronized( LOCK ) { // work What is the scope of LOCK? }
  16. 16. DO NOT: synch on autoboxed vals private static final Integer LOCK = 0; synchronized( LOCK ) { What is the scope of LOCK? // work }
  17. 17. DO NOT: synch on ReentrantLock Lock lock = new ReentrantLock(); synchronized(lock) { // ... Probably not what you meant here } Lock lock = new ReentrantLock(); lock.lock(); Probably more like this... try { // ... } finally { lock.unlock(); }
  18. 18. What should I lock on? // The field you’re protecting private final Map map = ... synchronized(map) { // ...access map } // Explicit lock object private final Object lock = new Object(); synchronized(lock) { // ...modify state }
  19. 19. Visibility
  20. 20. Visibility problems int x = 5; Thread 1: if(x == 5) { x = 10; } Thread 2: System.out.println(x);
  21. 21. Visibility problems volatile int x = 5; Thread 1: if(x == 5) { x = 10; } Thread 2: System.out.println(x);
  22. 22. Inconsistent Synchronization public class SomeData { private final Map data = new HashMap(); public void set(String key, String value) { synchronized(data) { Protecting writes data.put(key, value); } } } public String get(String key) { return data.get(key); ...but not reads }
  23. 23. Double-checked locking public class Singleton { private static Singleton instance; } public static Singleton getInstance() { Attempt to avoid synchronization if(instance == null) { synchronized(Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; }
  24. 24. Double-checked locking public class Singleton { private static Singleton instance; } public static Singleton getInstance() { if(instance == null) { synchronized(Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; } READ READ WRITE
  25. 25. Double-checked locking - volatile public class Singleton { private static volatile Singleton instance; } public static Singleton getInstance() { if(instance == null) { synchronized(Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; }
  26. 26. Double-checked locking - initialize on demand public class Singleton { private static class SingletonHolder { private static final Singleton instance = new Singleton(); } } public static Singleton getInstance() { return SingletonHolder.instance; }
  27. 27. volatile arrays public final class VolatileArray { private volatile boolean[] vals; public void flip(int i) { Is the value of vals[i] vals[i] = true; visible to other threads? } } public boolean flipped(int i) { return vals[i]; }
  28. 28. Atomicity
  29. 29. Volatile counter public class Counter { private volatile int count; } public int next() { return count++; } Looks atomic to me!
  30. 30. AtomicInteger counter public class Counter { private AtomicInteger count = new AtomicInteger(); } public int next() { return count.getAndIncrement(); } Really atomic via encapsulation over multiple actions
  31. 31. Composing atomic actions public Object putIfAbsent( Hashtable table, Object key, Object value) { Hashtable is thread-safe if(table.containsKey(key)) { // already present, return existing table.get(key); return null; } } else { // doesn't exist, create new value return table.put(key, value); } READ READ WRITE
  32. 32. Composing atomic actions public Object putIfAbsent( Hashtable table, Object key, Object value) { Hashtable is thread-safe if(table.containsKey(key)) { // already present, return existing table.get(key); return null; } } else { // doesn't exist, create new value return table.put(key, value); } READ READ WRITE
  33. 33. Participate in lock public Object putIfAbsent( Hashtable table, Object key, Object value) { Hashtable is thread-safe } synchronized(table) { if(table.containsKey(key)) { table.get(key); return null; } else { return table.put(key, value); } }
  34. 34. Encapsulated compound actions public Object putIfAbsent( ConcurrentHashMap table, Object key, Object value) { } return table.putIfAbsent(key, value); Encpasulation FTW!
  35. 35. Assignment of 64 bit values public class LongAssignment { private long x; public void setLong(long val) { x = val; Looks atomic to me, } but is it? }
  36. 36. Assignment of 64 bit values - volatile public class LongAssignment { private volatile long x; public void setLong(long val) { x = val; } }
  37. 37. Safe publication
  38. 38. Listener in constructor public interface DispatchListener { void newFare(Customer customer); } public class Taxi implements DispatchListener { public Taxi(Dispatcher dispatcher) { dispatcher.registerListener(this); We just published a // other initialization reference to this...oops! } } public void newFare(Customer customer) { // go to new customer’s location }
  39. 39. Starting thread in constructor public class Cache { private final Thread cleanerThread; public Cache() { cleanerThread = new Thread(new Cleaner(this)); cleanerThread.start(); this escapes again! } } // Clean will call back to this method public void cleanup() { // clean up Cache }
  40. 40. Static factory method public class Cache { // ... } public static Cache newCache() { Cache cache = new Cache(); cache.startCleanerThread(); return cache; }
  41. 41. Areas of Focus • Shared Data • Coordination • Performance { • Threads • Wait/notify
  42. 42. Threads
  43. 43. • THOU SHALT NOT: • call Thread.stop() • call Thread.suspend() or Thread.resume() All monitors unlocked by ThreadDeath Can lead to deadlock • call Thread.destroy() • call Thread.run() • use ThreadGroups Not implemented (or safe) Wonʼt start Thread! Still in caller Thread. Use a ThreadPoolExecutor instead.
  44. 44. wait/notify // Thread 1 synchronized(lock) { You must synchronize. while(! someCondition()) { Always wait in a loop. lock.wait(); } } // Thread 2 synchronized(lock) { Synchronize here too! satisfyCondition(); lock.notifyAll(); }
  45. 45. Condition is similar private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); public void waitTillChange() { lock.lock(); try { while(! someCondition()) condition.await(); } finally { lock.unlock(); Condition is more } flexible than wait/notify. } public void change() { lock.lock(); try { satisfyCondition(); condition.signalAll(); } finally { lock.unlock(); } }
  46. 46. Areas of Focus • Shared Data • Coordination • Performance { • Deadlock • Spin wait • Thread contention
  47. 47. Deadlock // Thread 1 synchronized(lock1) { synchronized(lock2) { // stuff } } // Thread 2 synchronized(lock2) { synchronized(lock1) { // stuff } } Classic deadlock.
  48. 48. Deadlock avoidance • Lock splitting • Lock ordering • Lock timeout • tryLock
  49. 49. Spin wait // Not efficient private volatile boolean flag = false; public void waitTillChange() { while(! flag) { Spin on flag, waiting for Thread.sleep(100); a change. } } public void change() { flag = true; }
  50. 50. Replace with Condition private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private boolean flag = false; public void waitTillChange() { lock.lock(); try { while(! flag) condition.await(); } finally { lock.unlock(); } } public void change() { lock.lock(); try { flag = true; condition.signalAll(); } finally { lock.unlock(); } } Better but longer.
  51. 51. CountDownLatch private final CountDownLatch latch = new CountDownLatch(1); public void waitTillChange() { latch.await(); } public void change() { latch.countDown(); } Coordination classes like CountDownLatch and CyclicBarrier cover many common uses better than Condition.
  52. 52. Lock contention x Hash f(x) Bucket 0 Bucket 1 Bucket 2 Bucket 3
  53. 53. Lock striping x Hash g(x) Hash f(x) Bucket 0 Bucket 1 Hash f(x) Bucket 0 Bucket 1
  54. 54. Final Exam public class StatisticsImpl implements Statistics, StatisticsImplementor { private long queryExecutionCount; public synchronized void queryExecuted( String hql, int rows, long time) { queryExecutionCount++; // ... other stat collection } public long getQueryExecutionCount() { return queryExecutionCount; } } public synchronized void clear() { queryExecutionCount = 0; // ... clear all other stats }
  55. 55. Final Exam public class StatisticsImpl implements Statistics, StatisticsImplementor { private long queryExecutionCount; Single shared lock for ALL stat values public synchronized void queryExecuted( String hql, int rows, long time) { queryExecutionCount++; // ... other stat collection } public long getQueryExecutionCount() { return queryExecutionCount; Read shared value } Non-atomic read w/o synchronization of long value } public synchronized void clear() { queryExecutionCount = 0; Race condition if reading // ... clear all other stats stat and clearing }
  56. 56. Thanks... Twitter Blog Concurrency links http://twitter.com/puredanger http://tech.puredanger.com http://concurrency.tumblr.com Refcard http://refcardz.dzone.com/refcardz/ core-java-concurrency Slides http://slideshare.net/alexmiller
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×