java™ platform concurrency gotchas - oracle · java™ platform concurrency gotchas alex miller...

54
Java™ Platform Concurrency Gotchas Alex Miller Terracotta

Upload: others

Post on 03-Jun-2020

65 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Java™ PlatformConcurrency Gotchas

Alex Miller Terracotta

Page 2: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Questions to answer

> What are common concurrency problems?> Why are they problems?> How do I detect these problems?> How do I correct these problems?

2

Page 3: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Taxonomy of Concurrency Gotchas

> Shared Data> Coordination> Performance

3

Page 4: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Shared Data

> Locking> Visibility> Atomicity> Safe Publication

4

Page 5: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

What happens if we modify data without locking?

5

Page 6: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

What happens if we modify data without locking?

5

Hint: itʼs not good.

Page 7: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

6

Page 8: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Mutable Statics

7

public class MutableStatics {

private static final DateFormat FORMAT = DateFormat.getDateInstance(DateFormat.MEDIUM);

public static Date parse(String str) throws ParseException { return FORMAT.parse(str); }

public static void main(String arg[]) { MutableStatics.parse(“Jan 1, 2000”); }}

FORMAT is mutable

...and this mutates it outside synchronization

Page 9: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Mutable Statics - instance per call

8

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[]) { MutableStatics.parse(“Jan 1, 2000”); }}

Page 10: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Synchronization

9

private int myField;

synchronized( ) {

myField = 0;

}

What goes here?

Page 11: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

DO NOT synchronize on null

10

MyObject obj = null;

synchronized( obj ) {

// stuff

}

NullPointerException!

Page 12: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

DO NOT change instance

11

MyObject obj = new MyObject();

synchronized( obj ) {

obj = new MyObject();

}

No longer synchronizing on the same object!

Page 13: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

12

Page 14: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

DO NOT synchronize on string literals

13

private static final String LOCK = “LOCK”;

synchronized( LOCK ) {

// work

}

What is the scope of LOCK?

Page 15: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

DO NOT synchronize on autoboxed instances

14

private static final Integer LOCK = 0;

synchronized( LOCK ) {

// work

}

What is the scope of LOCK?

Page 16: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

DO NOT synchronize on ReentrantLock

15

final Lock lock = new ReentrantLock();synchronized( lock ) { // work }

final Lock lock = new ReentrantLock();lock.lock();try { // ...} finally { lock.unlock();}

Probably not what you meant here

Probably should be this instead

Page 17: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

What should I lock on?

16

// The field you are protectingprivate final Map map = ...synchronized(map) { // ...access map}

// Or an explicit lock objectprivate final Object lock = new Object();synchronized(lock) { // ... modify state}

Page 18: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Visibility

17

Page 19: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Inconsistent Synchronization

18

public class SomeData { private final Map data = new HashMap();

public void put(String key, String value) { synchronized(data) { data.put(key, value); } }

public String get(String key) { return data.get(key); }}

Modified under synchronization

Read without synchronization

Page 20: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

public final class Singleton { private static Singleton instance;

public static Singleton getInstance() { if(instance == null) { synchronized(Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; }}

Double-checked locking

19

Attempt to avoid synchronization

Page 21: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

public final class Singleton { private static Singleton instance;

public static Singleton getInstance() { if(instance == null) { synchronized(Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; }}

Double-checked locking

19

READ

READWRITE

Page 22: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Double-checked locking - volatile

20

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

Page 23: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Double-checked locking - initialize on demand

21

public class Singleton {

private static class SingletonHolder { private static final Singleton instance = new Singleton(); }

public static Singleton getInstance() { return SingletonHolder.instance; }}

Page 24: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Racy single-check

22

public final class String { private int hash; // default to 0 private final char[] value; // immutable

public int hashCode() { int h = hash; if(h == 0) { // ... compute value for h from data hash = h; } return h; }}

Page 25: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

volatile arrays

23

public final class VolatileArray { private volatile boolean[] vals;

public void flip(int i) { vals[i] = true; } public boolean flipped(int i) { return vals[i]; }}

Is the value of vals[i] visible to other threads?

Page 26: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Atomicity

24

Page 27: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Volatile counter

25

public class Counter {

private volatile int count;

public int next() {

return count++;

}

}

Looks atomic to me!

Page 28: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

AtomicInteger counter

26

public class Counter {

private final AtomicInteger count = new AtomicInteger();

public int next() {

return count.getAndIncrement();

}

}

Really atomic by encapsulating multiple actions

Page 29: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Composing atomic actions

27

public Object putIfAbsent(Hashtable table, Object key, Object value) {

if(table.containsKey(key)) {// already present, return existing valuereturn table.get(key);

} else {// doesn’t exist, create and return new valuetable.put(key, value);return value;

}}

Hashtable is thread-safeREAD

WRITE

READ

Page 30: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Composing atomic actions

27

public Object putIfAbsent(Hashtable table, Object key, Object value) {

if(table.containsKey(key)) {// already present, return existing valuereturn table.get(key);

} else {// doesn’t exist, create and return new valuetable.put(key, value);return value;

}}

Hashtable is thread-safeREAD

WRITE

READ

Page 31: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Participate in lock

28

public Object putIfAbsent(Hashtable table, Object key, Object value) {

synchronized(table) {if(table.containsKey(key)) {

return table.get(key);} else {

table.put(key, value);return value;

}}

}

Protect with synchronization

Page 32: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Encapsulated compound actions

29

public Object putIfAbsent(

ConcurrentHashMap table, Object key, Object value) {

table.putIfAbsent(key, value);

}

Page 33: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Assignment of 64 bit values

30

public class LongAssignment {

private long x;

public void setLong(long val) {

x = val;

}

}

Looks atomic to me - but is it?

Page 34: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Assignment of 64 bit values - volatile

31

public class LongAssignment {

private volatile long x;

public void setLong(long val) {

x = val;

}

}

Page 35: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Safe publication

32

Intentionally left blank.

Page 36: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Listener in constructor

33

public interface DispatchListener { void newFare(Customer customer);}

public class Taxi implements DispatchListener { public Taxi(Dispatcher dispatcher) { dispatcher.registerListener(this); // other initialization }

public void newFare(Customer customer) { // go to new customer's location }}

We just published a reference to this - oops!

Page 37: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Starting thread in constructor

34

public class Cache { private final Thread cleanerThread;

public Cache() { cleanerThread = new Thread(new Cleaner(this)); cleanerThread.start(); }

// Cleaner calls back to this method public void cleanup() { // clean up Cache }}

this escapes again!

Page 38: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Static factory method

35

public class Cache {

// ...

public static Cache newCache() {

Cache cache = new Cache();

cache.startCleanerThread();

return cache;

}

}

Page 39: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Coordination

> Threads> wait/notify

36

Page 40: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Threads

> DO NOT:• Call Thread.stop()• Call Thread.suspend() or Thread.resume()• Call Thread.destroy()• Call Thread.run()• Use ThreadGroups

37

Page 41: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

wait/notify

38

// Thread 1

synchronized(lock) {

while(! someCondition()) {

lock.wait();

}

}

// Thread 2

synchronized(lock) {

satisfyCondition();

lock.notifyAll();

}

You must synchronize.Always wait in a loop.

Synchronize here too.

Update condition!

Page 42: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Performance

> Deadlock> Spin wait> Lock contention

39

Page 43: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Deadlock

40

// Thread 1

synchronized(lock1) {

synchronized(lock2) {

// stuff

}

}

// Thread 2

synchronized(lock2) {

synchronized(lock1) {

// stuff

}

}

Classic deadlock.

Page 44: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Deadlock avoidance

> Lock splitting> Lock ordering> Lock timeout> tryLock

41

Page 45: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Spin wait

42

// Not efficient

private volatile boolean flag = false;

public void waitTillChange() {

while(! flag) {

Thread.sleep(100);

}

}

public void change() {

flag = true;

}

Spin on flag, waiting for change

Page 46: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Replace with wait/notify

43

private final Object lock = new Object();private boolean flag = false;

public void waitTillChange() { synchronized(lock) { while(! flag) lock.wait(); }}

public void change() { synchronized(lock) { flag = true; lock.notifyAll(); }}

Wait/notify is far more efficient than spin wait.

Page 47: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Lock contention

44

Bucket 0 Bucket 1 Bucket 2 Bucket 3

Hash f(x)

x

Page 48: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Lock striping

45

Bucket 0 Bucket 1

Hash f(x)

Bucket 0 Bucket 1

Hash f(x)

Hash g(x)

x

Page 49: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Final Exam

46

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 } }

Page 50: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Final Exam

46

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 } }

Read of shared value without synchronization

Page 51: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Final Exam

46

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 } }

Read of shared value without synchronization

Non-atomic read of long value

Page 52: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Final Exam

46

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 } }

Read of shared value without synchronization

Non-atomic read of long value

Race condition if reading stat and clearing - could be compound action

Page 53: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Final Exam

46

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 } }

Read of shared value without synchronization

Non-atomic read of long value

Race condition if reading stat and clearing - could be compound action

Single shared lock for ALL stat values

Page 54: Java™ Platform Concurrency Gotchas - Oracle · Java™ Platform Concurrency Gotchas Alex Miller Terracotta. Questions to answer > What are common concurrency problems? > Why are

Alex MillerTerracotta

Blog: http://tech.puredanger.comTwitter: @puredanger