24
Concurrency Antipatterns in IDEA Почему все криво, ничего не работает и падает

Concurrency Antipatterns In IDEA

  • Upload
    cdracm

  • View
    579

  • Download
    3

Embed Size (px)

Citation preview

Page 1: Concurrency Antipatterns In IDEA

Concurrency Antipatternsin IDEA

Почему все криво,

ничего не работает и падает

Page 2: Concurrency Antipatterns In IDEA

Plan

• Theory– Concurrency primitives

• Antipatterns found in IDEA– Bad code– How to fix– What happened

• Bits of advice

Page 3: Concurrency Antipatterns In IDEA

Concurrency primitives

Mutual exclusion/general:• synchronized blocks – use always• j.u.c.locks.Lock – only for guruIn addition, for data protection:• j.u.c.* collections - use always• Atomic* classes – use rarely • volatile fields – never use

Page 4: Concurrency Antipatterns In IDEA

Antipattern

volatile T myCached;

public T getData() {

if (myCached == null) {

myCached = compute();

}

return myCached;

}

void clearCaches() {

myCached = null;

}

Page 5: Concurrency Antipatterns In IDEA

How to fix

/*not volatile*/ T myCached;

public synchronized T getData() {

if (myCached == null) {

myCached = compute();

}

return myCached;

}

void synchronized clearCaches() {

myCached = null;

}

Page 6: Concurrency Antipatterns In IDEA

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 myInitializedThe only state change is false->true

– Object publicationState change: null->initialized object

– Couple of other use cases$5 off salary per every usage

Page 7: Concurrency Antipatterns In IDEA

Antipattern

private T myInstance;

public T getData() {

if (myInstance == null) {

synchronized (this) {

if (myInstance == null) {

myInstance = init();

}}

}

return myInstance;

}

Page 8: Concurrency Antipatterns In IDEA

How to fix

private volatile T myInstance;

public T getData() {

if (myInstance == null) {

synchronized (this) {

if (myInstance == null) {

myInstance = init();

}}

}

return myInstance;

}

Page 9: Concurrency Antipatterns In IDEA

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 for using DCL

Page 10: Concurrency Antipatterns In IDEA

Antipattern

private T myData;

public void populateCache() {

synchronized (lock) {

myData = compute(); }

}

public T getData() {

return myData;

}

Page 11: Concurrency Antipatterns In IDEA

How to fix

private T myData;

public void populateCache() {

synchronized (lock) {

myData = compute(); }

}

public T getData() {

synchronized (lock) {

return myData; }

}

Page 12: Concurrency Antipatterns In IDEA

Moral

Half-baked synchronization

Both threads must synchronize on same lock for changes to be visible

$10 off salary per every usage

Page 13: Concurrency Antipatterns In IDEA

Antipattern

private T myData;

public MyClass() {

myData = init(); }

}

public T getData() {

return myData;

}

Page 14: Concurrency Antipatterns In IDEA

How to fix

private final T myData;

public MyClass() {

myData = init(); }

}

public T getData() {

return myData;

}

Page 15: Concurrency Antipatterns In IDEA

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

Page 16: Concurrency Antipatterns In IDEA

Antipatternprivate 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(); }

}

Page 17: Concurrency Antipatterns In IDEA

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(); }

}

Page 18: Concurrency Antipatterns In IDEA

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

Page 19: Concurrency Antipatterns In IDEA

Antipattern (not really)

private int myCounter;

public synchronized void increment() {

myCounter++;

}

public synchronized int getValue() {

return myCounter;

}

Page 20: Concurrency Antipatterns In IDEA

How to /*fix*/ simplify

private final AtomicInteger myCounter;

public void increment() {

myCounter.incrementAndGet();

}

public int getValue() {

return myCounter.get();

}

Page 21: Concurrency Antipatterns In IDEA

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

Page 22: Concurrency Antipatterns In IDEA

Bits of advice

• Use CopyOnWriteArrayList instead of synchronized accessors for rarely modified lists, e.g. listeners

• Use ConcurrentHashMap instead of Collections.synchronizedMap()

Page 23: Concurrency Antipatterns In IDEA

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!

Page 24: Concurrency Antipatterns In IDEA

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