Concurrency Antipatterns In IDEA

877 views

Published on

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

No Downloads
Views
Total views
877
On SlideShare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
10
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Concurrency Antipatterns In IDEA

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

×