concurrent programming without synchronization
Post on 13-Apr-2017
146 Views
Preview:
TRANSCRIPT
1CONFIDENTIAL
CONCURRENT PROGRAMMING
WITHOUT SYNCHRONIZATION
JENI MARKISHKA
MARTIN HRISTOVJULY 4, 2015
2CONFIDENTIAL
THREAD SAFETY?
WHAT IS
3CONFIDENTIAL
THREAD SAFETY
• … is unfortunately hard to be
defined.
• Because it means different things to
different people!
• Brian Goetz:
• A class is thread-safe when it continues to behave
correctly when accessed from multiple threads.
• Joseph Albahari:
• A program or method is thread-safe if it has no
indeterminacy in the face of any multithreading
scenario.
Image credit: http://www.beaconhillnw.com/2014/09/workplace-safety-signage/
4CONFIDENTIAL
ALL ABOUT DATA INTEGRITY!
THREAD SAFETY IS
5CONFIDENTIAL
THREAD SAFETY?
BUT HOW DO WE ACHIEVE
6CONFIDENTIAL
THREAD SAFETY?
BUT HOW DO WE ACHIEVE
> MUTEXES
> LOCK-FREE MECHANISMS
7CONFIDENTIAL
LOCK-FREE THREAD SAFETY
Immutability1
Compare-And-Swap (CAS)2
volatile piggy-backing3
Thread confinement4
• Ad-hoc Thread Confinement
• Stack Confinement
• Thread Confinement with ThreadLocal
8CONFIDENTIAL
IMMUTABILITY
• Immutable objects cannot change their state once constructed
• Strategy for definition:
• No setter methods
• All fields private and final
• No methods overriding allowed
• No this and mutable field references escapes
• Thread safety guaranteed by initialization safety (JSR-133)
• Safe and simple; consider whenever feasible
Image credit: https://www.flickr.com/photos/bala_/4184518104/
9CONFIDENTIAL
@ThreadSafepublic final class CreditCard {
private final String holder;private final String number;
public CreditCard(String holder,String number) {
this.holder = holder;this.number = number;
}
public String getHolder() {return holder;
}
public String getNumber() {return number;
}}
THREAD-SAFE
IMMUTABILITY (EXAMPLES)
NOT THREAD-SAFE
@NotThreadSafefinal public class ShoppingCart {
private CartService cartService;private final List<Item> items;
@Autowiredpublic ShoppingCart(List<Item> items,
CartService cs) {cartService = cs;cartService.registerCart(this);this.items = Collections
.unmodifiableList(items);}
public List<Item> getItems() {return items;
}}
10CONFIDENTIAL
@ThreadSafepublic final class CreditCard {
private final String holder;private final String number;
public CreditCard(String holder,String number) {
this.holder = holder;this.number = number;
}
public String getHolder() {return holder;
}
public String getNumber() {return number;
}}
THREAD-SAFE
IMMUTABILITY (EXAMPLES)
NOT THREAD-SAFE
@NotThreadSafefinal public class ShoppingCart {
private CartService cartService;private final List<Item> items;
@Autowiredpublic ShoppingCart(List<Item> items,
CartService cs) {cartService = cs;cartService.registerCart(this);this.items = Collections
.unmodifiableList(items);}
public List<Item> getItems() {return items;
}} Escape of mutable data object reference
Escape of this reference during construction
11CONFIDENTIAL
EFFECTIVE IMMUTABILITY
• A special case of immutability
• Effective immutability is a
characteristic of instances rather
than classes
• An object instance that cannot be
mutated via any execution path is
effectively immutable
• Effectively immutable objects are
instances of mutable classes
Image credit: https://www.flickr.com/photos/pupski/34237242/
12CONFIDENTIAL
@NotThreadSafepublic final class AirConditioner {
private final boolean canChange;private short temperature;
public AirConditioner(short temperature, boolean canChange) {this.canChange = canChange;this.temperature = temperature;
}
public void setTemperature(short newTemperature) {if (canChange) {
temperature = newTemperature;} else {
throw new IllegalStateException();}
}
public short getTemperature() {return temperature;
}}
EFFECTIVE IMMUTABILITY (EXAMPLE)
THREAD-SAFE INSTANCE
AirConditioner airConditioner =
new AirConditioner(24, false);
13CONFIDENTIAL
@NotThreadSafepublic final class AirConditioner {
private final boolean canChange;private short temperature;
public AirConditioner(short temperature, boolean canChange) {this.canChange = canChange;this.temperature = temperature;
}
public void setTemperature(short newTemperature) {if (canChange) {
temperature = newTemperature;} else {
throw new IllegalStateException();}
}
public short getTemperature() {return temperature;
}}
EFFECTIVE IMMUTABILITY (EXAMPLE)
THREAD-SAFE INSTANCE
AirConditioner airConditioner =
new AirConditioner(24, false);
14CONFIDENTIAL
COMPARE-AND-SWAP (CAS)
• Non-blocking algorithm for concurrent access to shared data
• Modifies a value in memory only if it is equal to a given value, otherwise the modification fails
• Ensures that the new value is calculated based on up-to-date data
• Uses atomic CPU instructions:• CMPXCHG (x86)• CMPXCHGQ (x64)
• Available via atomic variables in Java 5.0+ java.util.concurrent.atomic
Image credit: http://www.keepcalm-o-matic.co.uk/
15CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
CPU2
16CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
CPU2
read
17CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
21
CPU2
read
21
18CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
21
CPU2
19CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
21
CPU2
read
20CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
21
CPU2
21
read
ok
21CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
21
CPU2
21
22CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
21
CPU2
2122
23CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
22
CPU2
21
cas(21,22)
24CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
21
CPU2
21
cas(21,22)
22
ok
2222
25CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
21
CPU2
21
22
2222
22
26CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
21
CPU2
21
22
2222
22
20
27CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
21
CPU2
21
22
2222
22
20
cas(21,20)
28CONFIDENTIAL
CPU1
CAS EXPLAINED
MEMORY
21
21
CPU2
21
22
2222
22
20
cas(21,20)
write
failed
29CONFIDENTIAL
@ThreadSafepublic class AtomicCounter {
private final AtomicInteger value =new AtomicInteger(0);
public int getValue() {return value.get();
}
public int increment() {return value.incrementAndGet();
}}
THREAD-SAFE
CAS vs volatile (EXAMPLES)
NOT THREAD-SAFE
@NotThreadSafepublic class VolatileCounter {
private volatile int value = 0;
public int getValue() {return value;
}
public int increment() {return value++;
}}
30CONFIDENTIAL
@ThreadSafepublic class AtomicCounter {
private final AtomicInteger value =new AtomicInteger(0);
public int getValue() {return value.get();
}
public int increment() {return value.incrementAndGet();
}}
THREAD-SAFE
CAS vs volatile (EXAMPLES)
NOT THREAD-SAFE
@NotThreadSafepublic class VolatileCounter {
private volatile int value = 0;
public int getValue() {return value;
}
public int increment() {return value++;
}} • Unsafe operation
• The increment operator is not an
atomic action:
• Read value
• Increment by 1
• Write value
• Volatile ensures visibility only and not
atomicity
31CONFIDENTIAL
@ThreadSafepublic class VolatileCounter {
private volatile int value = 0;
public int getValue() {return value;
}
public synchronized int increment() {return value++;
}}
@ThreadSafepublic class AtomicCounter {
private final AtomicInteger value =new AtomicInteger(0);
public int getValue() {return value.get();
}
public int increment() {return value.incrementAndGet();
}}
THREAD-SAFE
CAS vs volatile (EXAMPLES)
THREAD-SAFE
Lock contention == performance degradation
32CONFIDENTIAL
VOLATILE PIGGY-BACKING
• Allows volatile-like semantics for non-volatile variables
• Exploits the happens-before order established by JSR-133
• Actions in the same thread cannot be reordered (Program order)
• A write to a volatile field
happens-before every
subsequent read of that field
• Volatile writes effectively
create a memory fence
which flushes CPU cache
Image credit: http://www.magic-of-color.com/?p=2127
33CONFIDENTIAL
public class Point {
private int x;private int y;
private volatile boolean done = false;
public void calculateCoordinates() {x = someHeavyweightAlgorithm(…); // x=5y = someHeavyweightAlgorithm(…); // y=10sync();
}
private void sync() {done = true;
}
public int getX() { return x; }public int getY() { return y; }public boolean isDone() { return done; }
}
THREAD #1
VOLATILE PIGGY-BACKING (EXAMPLE)
THREAD #2
public class CoordinatesConsumer {private Point point;
public CoordinatesConsumer(Point point) {this.point = point;
}
public void doSomething() {while (!point.isDone()) ; // Busy waitint x = point.getX(); // x=5int y = point.getY(); // y=10
}}
• x and y get visible in Thread #2 even
though they are not volatile
• they piggyback on done which is volatile
34CONFIDENTIAL
VOLATILE PIGGY-BACKING PRECAUTIONS
• Volatile piggybacking is fragile! Use at your own risk!
• Ensures only visibility, thus applicable for “single writer /
multiple readers” scenarios only
• It does not ensure compound atomicity in case of multiple
writes/reads.
Image credit: http://www.noomii.com/blog/5949-warning-union-info-centre-scam
35CONFIDENTIAL
THREAD CONFINEMENT
• Thread confinement is a simple yet powerful technique used
to achieve thread safety without synchronization.
• The simple idea:
• If data is only accessed from a single thread,
no synchronization is needed.
• Examples:
• Swing – visual components are confined to the event
dispatch thread
• JDBC Connection Pools
36CONFIDENTIAL
CONFINEMENT MECHANISMS
• Java does not provide language-level
mechanisms that enforce thread
confinement.
• Must be enforced by the application
design and its implementation
• Java provides mechanisms that help maintaining confinement:
• Access modifiers
• Local variables
• ThreadLocal
Image credit: http://www.treatmentadvocacycenter.org/about-us/our-blog/69-no-state/2109-solitary-confinement-like-gasoline-on-fire
37CONFIDENTIAL
AD-HOC THREAD CONFINEMENT
• Developer is completely responsible to confine object to
thread. Language features (like local variables, access
modifiers) are not used
• State must be shared in a specific way:
• All shared data – marked as volatile
• Only a single thread must be able to write to the
shared data - requires developer’s carefulness and
discipline
• Not recommended approach (due to its fragility)
38CONFIDENTIAL
STACK CONFINEMENT
• Special case of thread
confinement
• An object can only be
reached through a
local variable
• The developer must
ensure that the object
reference does not
escape the method
• Ensures thread safety even if the confined object itself is not
thread-safe
39CONFIDENTIAL
STACK CONFINEMENT
• Example:
public static String format(Date date) {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
return df.format(date);
}
• We only have one reference to the SimpleDateFormat object
• The reference is held in a local variable and therefore confined
to the executing thread
40CONFIDENTIAL
STACK CONFINEMENT
private static final DateFormat df =
new SimpleDateFormat("yyyy-MM-dd");
public static String format(Date date) {
return df.format(date);
}
41CONFIDENTIAL
STACK CONFINEMENT
private static final DateFormat df =
new SimpleDateFormat("yyyy-MM-dd");
public static String format(Date date) {
return df.format(date);
}
No longer
“stack confined”
42CONFIDENTIAL
THREAD CONFINEMENT WITH ThreadLocal
java.lang.ThreadLocal<T>:
• Provides thread-local variables
• Each thread has its own, independently initialized copy
of the variable (accessed via ThreadLocal’s get() or
set() methods)
• ThreadLocal instances are typically private static fields
in classes that wish to associate state with a thread
43CONFIDENTIAL
THREAD CONFINEMENT WITH ThreadLocal
Example: DateFormat is not thread-safe, so we use thread
confinement:
private static final ThreadLocal<DateFormat> tdf =
new ThreadLocal<DateFormat>() {
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};
public String threadConfined(Date date) {
return tdf.get().format(date);
}
44CONFIDENTIAL
OBJECT ESCAPE
• An object is said to have escaped if it is published before
intended.
Image credit: http://www.humbersidefire.gov.uk/your-safety/safety-in-the-home/escape
45CONFIDENTIAL
OBJECT ESCAPE (EXAMPLE)
• Store a reference in a public static field, where any class and thread
could see it:
public static List<String> unsafeList;
public void initialize() {
unsafeList = new ArrayList<String>();
}
• Return a reference from a non-private method:
class UnsafeCurrencies {
private String[] currencies = new String[] {"USD",
"GBP", "BGN", "EUR", "AUD"};
public String[] getCurrencies() { return currencies; }
}
46CONFIDENTIAL
JAVA
OBJECT ESCAPE (EXAMPLE)
BYTECODE
…final com.threadconfinement.ThisEscape this$0;
…0: aload_01: aload_12: putfield #1// Field this$0:Lcom/threadconfinement/ThisEscape;5: aload_06: invokespecial #2// Method java/lang/Object."<init>":()V9: return…
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
}
}
47CONFIDENTIAL
JAVA
OBJECT ESCAPE (EXAMPLE)
BYTECODE
…final com.threadconfinement.ThisEscape this$0;
…0: aload_01: aload_12: putfield #1// Field this$0:Lcom/threadconfinement/ThisEscape;5: aload_06: invokespecial #2// Method java/lang/Object."<init>":()V9: return…
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
}
}
48CONFIDENTIAL
BENEFITS
• No accidental complexitySIMPLICITY2
1
• No lock contention
• Scales really well due to the lack of
synchronization overhead
PERFORMANCE
& SCALABILITY
3 • No race conditionsNO RISK OF
DEADLOCKS
49CONFIDENTIAL
THE END
top related