Concurrency Antipatterns in IDEA Почему все криво,  ничего не работает и падает
Plan Theory Concurrency primitives Antipatterns found in IDEA Bad code How to fix What happened  Bits of advice
Concurrency primitives Mutual exclusion/general: synchronized  blocks – use always j.u.c.locks.Lock  – only for guru In addition, for data protection: j.u.c .* collections  - use always Atomic * classes – use rarely  volatile  fields – never use
Antipattern volatile  T myCached; public  T getData() { if  (myCached ==  null ) { myCached = compute(); } return  myCached; } void  clearCaches() { myCached =  null ; }
How to fix /*not volatile*/  T myCached; public   synchronized  T getData() { if  (myCached ==  null ) { myCached = compute(); } return  myCached; } void   synchronized  clearCaches() { myCached =  null ; }
Moral volatile  properties Visibility Disallowed reordering But: more expensive access Use  volatile  only when value do not depend on previous state or other variables, e.g. Boolean flag myInitialized The only state change is false->true Object publication State change: null->initialized object Couple of other use cases $5 off salary per every usage
Antipattern private  T myInstance; public  T getData() { if  (myInstance ==  null ) { synchronized  ( this ) { if  (myInstance ==  null ) { myInstance = init(); }} } return  myInstance; }
How to fix private   volatile  T myInstance; public  T getData() { if  (myInstance ==  null ) { synchronized  ( this ) { if  (myInstance ==  null ) { myInstance = init(); }} } return  myInstance; }
Moral Why DCL is broken: myInstance = new T();    (compiles to) m = alloc(T.class); m.x = 2; //inline constructor myInstance = m;    (if myInstance not volatile, can reorder) m = alloc(T.class); myInstance = m; //not initialized obj escapes m.x = 2; 5 min  whipping f or using DCL
Antipattern private  T myData; public   void  populateCache() { synchronized  (lock) { myData = compute(); } } public  T getData() { return  myData; }
How to fix private  T myData; public   void  populateCache() { synchronized  (lock) { myData = compute(); } } public  T getData() { synchronized  (lock)  { return  myData; } }
Moral Half-baked synchronization Both threads must synchronize on  same  lock for changes to be visible $10 off salary per every usage
Antipattern private  T myData; public   MyClass () { myData = init(); } } public  T getData() { return  myData; }
How to fix private   final  T myData; public   MyClass () { myData = init(); } } public  T getData() { return  myData; }
Moral Safe object publication Java undertakes special measures to make final fields safely initialized and visible after constructor execution.  knocking head against table 5 times for every non final field
Antipattern private  T myCollection; public   void  addItem() { //once in a blue moon try  { lock.lock(); myCollection.addSomething(); }  finally  { lock.unlock(); }} public  T   findSomething() { //constantly try  { lock.lock(); return  myCollection.findSomething(); }  finally  { lock.unlock(); } }
How to fix private  T myCollection; public   void  addItem() { //once in a blue moon try  {  lock.getWriteLock() .lock(); myCollection.addSomething(); }  finally  {  lock.getWriteLock() .unlock(); }} public  T   findSomething() { //constantly try  {  lock.getReadLock() .lock(); return  myCollection.findSomething(); }  finally  {  lock.getReadLock() .unlock(); } }
Moral Read/Write locking Use when write access is infrequent, whereas read access is overwhelmingly typical. E.g. listener lists, some caches. 5 minutes of contempt for each overlooked usage
Antipattern (not really) private  int myCounter; public   synchronized void  increment() {  myCounter++; } public   synchronized  int   getValue() {  return  myCounter; }
How to /*fix*/ simplify private   final AtomicInteger  myCounter; public   void  increment() {  myCounter.incrementAndGet(); } public  int   getValue() {  return  myCounter.get(); }
Moral Atomic* classes are handy Implemented via hardware-supported CAS (compare and swap) instruction Cheap under low contention Can saturate processor bus in multicore environment and high contention
Bits of advice Use  CopyOnWriteArrayList  instead of synchronized accessors for rarely modified lists, e.g. listeners Use  ConcurrentHashMap  instead of Collections.synchronizedMap()
Bits of advice Is  ReentrantLock  better than  synchronized ? +1  More scalable under high contention +1  More features: interruptible, timed wait, polling multiple, not structured -1  Some clever optimizations are not yet available for Locks: lock coarsening, lock elision, adaptive spinning -1  Ugly error-prone syntax Resolution : use *Locks only if need advanced features, otherwise stick with synchronized. Profile!
Bugs are everywhere For more concurrency antipatterns, see IDEA source base. Read Brian Goetz – he is clever. More flexible, scalable locking in JDK5: www.ibm.com/developerworks/java/library/j-jtp10264 Managing volatility: www.ibm.com/developerworks/java/library/j-jtp06197.html

Concurrency Antipatterns In IDEA

  • 1.
    Concurrency Antipatterns inIDEA Почему все криво, ничего не работает и падает
  • 2.
    Plan Theory Concurrencyprimitives Antipatterns found in IDEA Bad code How to fix What happened Bits of advice
  • 3.
    Concurrency primitives Mutualexclusion/general: synchronized blocks – use always j.u.c.locks.Lock – only for guru In addition, for data protection: j.u.c .* collections - use always Atomic * classes – use rarely volatile fields – never use
  • 4.
    Antipattern volatile T myCached; public T getData() { if (myCached == null ) { myCached = compute(); } return myCached; } void clearCaches() { myCached = null ; }
  • 5.
    How to fix/*not volatile*/ T myCached; public synchronized T getData() { if (myCached == null ) { myCached = compute(); } return myCached; } void synchronized clearCaches() { myCached = null ; }
  • 6.
    Moral volatile properties Visibility Disallowed reordering But: more expensive access Use volatile only when value do not depend on previous state or other variables, e.g. Boolean flag myInitialized The only state change is false->true Object publication State change: null->initialized object Couple of other use cases $5 off salary per every usage
  • 7.
    Antipattern private T myInstance; public T getData() { if (myInstance == null ) { synchronized ( this ) { if (myInstance == null ) { myInstance = init(); }} } return myInstance; }
  • 8.
    How to fixprivate volatile T myInstance; public T getData() { if (myInstance == null ) { synchronized ( this ) { if (myInstance == null ) { myInstance = init(); }} } return myInstance; }
  • 9.
    Moral Why DCLis broken: myInstance = new T();  (compiles to) m = alloc(T.class); m.x = 2; //inline constructor myInstance = m;  (if myInstance not volatile, can reorder) m = alloc(T.class); myInstance = m; //not initialized obj escapes m.x = 2; 5 min whipping f or using DCL
  • 10.
    Antipattern private T myData; public void populateCache() { synchronized (lock) { myData = compute(); } } public T getData() { return myData; }
  • 11.
    How to fixprivate T myData; public void populateCache() { synchronized (lock) { myData = compute(); } } public T getData() { synchronized (lock) { return myData; } }
  • 12.
    Moral Half-baked synchronizationBoth threads must synchronize on same lock for changes to be visible $10 off salary per every usage
  • 13.
    Antipattern private T myData; public MyClass () { myData = init(); } } public T getData() { return myData; }
  • 14.
    How to fixprivate final T myData; public MyClass () { myData = init(); } } public T getData() { return myData; }
  • 15.
    Moral Safe objectpublication Java undertakes special measures to make final fields safely initialized and visible after constructor execution. knocking head against table 5 times for every non final field
  • 16.
    Antipattern private T myCollection; public void addItem() { //once in a blue moon try { lock.lock(); myCollection.addSomething(); } finally { lock.unlock(); }} public T findSomething() { //constantly try { lock.lock(); return myCollection.findSomething(); } finally { lock.unlock(); } }
  • 17.
    How to fixprivate T myCollection; public void addItem() { //once in a blue moon try { lock.getWriteLock() .lock(); myCollection.addSomething(); } finally { lock.getWriteLock() .unlock(); }} public T findSomething() { //constantly try { lock.getReadLock() .lock(); return myCollection.findSomething(); } finally { lock.getReadLock() .unlock(); } }
  • 18.
    Moral Read/Write lockingUse when write access is infrequent, whereas read access is overwhelmingly typical. E.g. listener lists, some caches. 5 minutes of contempt for each overlooked usage
  • 19.
    Antipattern (not really)private int myCounter; public synchronized void increment() { myCounter++; } public synchronized int getValue() { return myCounter; }
  • 20.
    How to /*fix*/simplify private final AtomicInteger myCounter; public void increment() { myCounter.incrementAndGet(); } public int getValue() { return myCounter.get(); }
  • 21.
    Moral Atomic* classesare handy Implemented via hardware-supported CAS (compare and swap) instruction Cheap under low contention Can saturate processor bus in multicore environment and high contention
  • 22.
    Bits of adviceUse CopyOnWriteArrayList instead of synchronized accessors for rarely modified lists, e.g. listeners Use ConcurrentHashMap instead of Collections.synchronizedMap()
  • 23.
    Bits of adviceIs ReentrantLock better than synchronized ? +1 More scalable under high contention +1 More features: interruptible, timed wait, polling multiple, not structured -1 Some clever optimizations are not yet available for Locks: lock coarsening, lock elision, adaptive spinning -1 Ugly error-prone syntax Resolution : use *Locks only if need advanced features, otherwise stick with synchronized. Profile!
  • 24.
    Bugs are everywhereFor more concurrency antipatterns, see IDEA source base. Read Brian Goetz – he is clever. More flexible, scalable locking in JDK5: www.ibm.com/developerworks/java/library/j-jtp10264 Managing volatility: www.ibm.com/developerworks/java/library/j-jtp06197.html