Download Understanding Java Thread Synchronization: Challenges and Best Practices - Prof. William P and more Quizzes Programming Languages in PDF only on Docsity!
1 TS-754, Correct and Efficient Synchronization of Java Threads
Correct and Efficient
Synchronization of
Java™^ Technology-
based Threads
Doug Lea and William Pugh
http://gee.cs.oswego.edu
http://www.cs.umd.edu/~pugh
2 TS-754, Correct and Efficient Synchronization of Java Threads
Audience
- Assume you are familiar with basics
of Java™^ technology-based threads
(“Java threads”)
- Creating, starting and joining threads
- Synchronization
- wait and notifyAll
- Will talk about things that surprised a lot
of experts
- Including us, James Gosling, Guy Steele, … (others discovered many of these)
3 TS-754, Correct and Efficient Synchronization of Java Threads
Java Thread Specification
- Chapter 17 of the Java Language Spec
- Chapter 8 of the Virtual Machine Spec
- Very, very hard to understand
- Not even the authors understood it
- Has subtle implications
- That forbid standard compiler optimizations
- All existing JVMs violate the specification
- Some parts should be violated
4 TS-754, Correct and Efficient Synchronization of Java Threads
Safety Issues in
Multithreaded Systems
- Many intuitive assumptions do not hold
- Some widely used idioms are not safe
- Double-check idiom
- Checking non-volatile flag for thread termination
- Can’t use testing to check for errors
- Some anomalies will occur only on some platforms - e.g., multiprocessors
5 TS-754, Correct and Efficient Synchronization of Java Threads
Revising the Thread Spec
- Work is underway to consider revising the
Java Thread Spec
- http://www.cs.umd.edu/~pugh/java/memoryModel
- Goals
- Clear and easy to understand
- Foster reliable multithreaded code
- Allow for high performance JVMs
- Will effect JVMs
- And badly written existing code
- Including parts of Sun’s JDK 6 TS-754, Correct and Efficient Synchronization of Java Threads
What to do Today?
- Guidelines we will provide should
work under both existing and future
thread specs
- Don’t try to read the official specs
- Avoid corner cases of the thread spec
- Not needed for efficient and reliable programs
7 TS-754, Correct and Efficient Synchronization of Java Threads
Three Aspects of
Synchronization
- Atomicity
- Locking to obtain mutual exclusion
- Visibility
- Ensuring that changes to object fields made in one thread are seen in other threads
- Ordering
- Ensuring that you aren’t surprised by the order in which statements are executed
8 TS-754, Correct and Efficient Synchronization of Java Threads
Don’t Be Too Clever
- People worry about the cost of
synchronization
- Try to devise schemes to communicate between threads - Without using synchronization
- Very difficult to do correctly
- Inter-thread communication without synchronization is not intuitive
9 TS-754, Correct and Efficient Synchronization of Java Threads
Quiz Time
x = y = 0
x = 1
j = y
Thread 1 y = 1
i = x
Thread 2
Can this result in i = 0 and j = 0?
start threads
10 TS-754, Correct and Efficient Synchronization of Java Threads
Answer: Yes!
x = y = 0
x = 1
j = y
Thread 1 y = 1
i = x
Thread 2
How can i = 0 and j = 0?
start threads
11 TS-754, Correct and Efficient Synchronization of Java Threads
How Can This Happen?
- Compiler can reorder statements
- Or keep values in registers
- Processor can reorder them
- On multi-processor, values not
synchronized in global memory
- Must use synchronization to enforce
visibility and ordering
- As well as mutual exclusion
12 TS-754, Correct and Efficient Synchronization of Java Threads
Synchronization Actions
( approximately )
// block until obtain lock synchronized(anObject) { // get main memory value of field1 and field int x = anObject.field1; int y = anObject.field2; anObject.field3 = x+y; // commit value of field3 to main memory } // release lock moreCode();
19 TS-754, Correct and Efficient Synchronization of Java Threads
Why Use Volatile?
- Since the semantics are implemented
inconsistently
- Future-proof your code
- Prohibit optimizations compilers might do in the future
- Works well for flags
- More complicated uses are tricky
- Revising the thread spec...
- Test compliance
- Strengthen to make easier to use 20 TS-754, Correct and Efficient Synchronization of Java Threads
Cost of Synchronization
- Few good public multithreaded
benchmarks
- See us if you want to help
- Volano Benchmark
- Most widely used server benchmark
- Multithreaded chat room server
- Client performs 4.8M synchronizations
- 8K useful (0.2%)
- Server 43M synchronizations
- 1.7M useful (4%)
21 TS-754, Correct and Efficient Synchronization of Java Threads
Synchronization in
VolanoMark Client
90.3%
5.6% 1.8% 0.9% 0.9% 0.4% 0.2%
java.io.BufferedInputStream java.io.BufferedOutputStream java.util.Observable java.util.Vector java.ioeveryth.FinilterIng elseputStream All shared monitors
7,684 synchronizations on shared monitors 4,828,130 thread local synchronizations
22 TS-754, Correct and Efficient Synchronization of Java Threads
Cost of Synchronization
in VolanoMark
- Removed synchronization of
- java.io.BufferedInputStream
- java.io.BufferedOutputStream
- Performance (2 processor Ultra 60)
- Larger is better
- HotSpot (1.3 beta)
- Original: 4788
- Altered: 4923 (+3%)
- Exact VM (1.2.2)
- Original: 6649
- Altered: 6874 (+3%)
23 TS-754, Correct and Efficient Synchronization of Java Threads
Most Synchronization is on
Thread Local Objects
- Synchronization on thread local object
- Is useless
- Current spec says it isn’t quite a no-op
- But very hard to use usefully
- Revised spec will likely make it a no-op
- Largely arises from using synchronized
classes
- In places where not required
24 TS-754, Correct and Efficient Synchronization of Java Threads
Synchronize when Needed
- Places where threads interact
- Need synchronization
- Need careful thought
- Need documentation
- Cost of required synchronization not significant
- For most applications
- No need to get tricky
- Elsewhere, using a synchronized class can
be expensive
25 TS-754, Correct and Efficient Synchronization of Java Threads
Synchronized Classes
- Some classes are synchronized
- Vector, Hashtable, Stack
- Most Input/Output Streams
- Contrast with 1.2 Collection classes
- By default, not synchronized
- Can request synchronized version
- Using synchronized classes
- Often doesn’t suffice for concurrent interaction
26 TS-754, Correct and Efficient Synchronization of Java Threads
Synchronized Collections
Aren’t Always Enough
- Transactions (DO NOT USE)
ID getID(String name) {
ID x = (ID) h.get(name);
if (x == null) {
x = new ID();
h.put(name, x);}
return x; }
- Iterators
- Can’t modify collection while another thread is iterating through it
27 TS-754, Correct and Efficient Synchronization of Java Threads
Concurrent Interactions
- Often need entire transactions to
be atomic
- Reading and updating a Map
- Writing a record to an OutputStream
- OutputStreams are synchronized
- Can have multiple threads trying to write to the same OutputStream
- Output from each thread is nondeterministicly interleaved
- Essentially useless
28 TS-754, Correct and Efficient Synchronization of Java Threads
Cost of Synchronization in
SpecJVM DB Benchmark
- Program in the Spec JVM benchmark
- Does lots of synchronization
53,000,000 syncs - 99.9% comes from use of Vector - Benchmark is single threaded, all of it is useless
- Tried
- Remove synchronizations
- Switching to ArrayList
- Improving the algorithm
29 TS-754, Correct and Efficient Synchronization of Java Threads
Execution Time of Spec JVM
_209_db, Hotspot Server
0
10
20
30
40
Original 35.5 32.6 28.5 16.2 12. Without Syncs 30.3^ 32.5^ 28.5^ 14.0^ 12.
Original (^) ArrayListUse ArrayListUse and otherminor Shell SortChange to MergeSort All
30 TS-754, Correct and Efficient Synchronization of Java Threads
Lessons
- Synchronization cost can be substantial
- 10-20% for DB benchmark
- Consider replacing all uses of Vector, Hashtable and Stack
- Use profiling
- Use better algorithms!
- Cost of stupidity higher than cost of synchronization
- Used built-in merge sort rather than hand-coded shell sort
37 TS-754, Correct and Efficient Synchronization of Java Threads
Initialization checks - v2 - OK
Isolate check: class ServiceV2 { Parser parser = null; synchronized Parser getParser() { if (parser == null) parser = new Parser(); return parser; } public void command(...) { doCommand(getParser().parse(...)); }} 38 TS-754, Correct and Efficient Synchronization of Java Threads
Single-check - DO NOT USE
Try to do it without synchronization: class ServiceV3 { // DO NOT USE Parser parser = null; Parser getParser() { if (parser == null) parser = new Parser(); return parser; }}
39 TS-754, Correct and Efficient Synchronization of Java Threads
Double-check - DO NOT USE
Try to minimize likelihood of synch: class ServiceV4 { // DO NOT USE Parser parser = null; Parser getParser() { if (parser == null) synchronized(this) { if (parser == null) parser = new Parser(); } return parser; }} 40 TS-754, Correct and Efficient Synchronization of Java Threads
Problems with Double-check
- Can reorder
- Initialization of Parser object
- Store into parser field
- …Among other reasons
- See JMM web page for gory details
- Can go wrong on uniprocessors
- Using volatile doesn’t help
41 TS-754, Correct and Efficient Synchronization of Java Threads
Alternatives to
Double–Check
- Use synchronization
- Double check OK for primitive values
- hashCode caching (still technically a data race)
- For static singletons
- Put in separate class
- First use of a class forces class initialization
- Later uses guaranteed to see class initialization
- No explicit check needed
42 TS-754, Correct and Efficient Synchronization of Java Threads
Rare Heavy New Objects
- Sometimes, need singleton that is
expensive to create
static final Font HELVETICA = new FONT(“Helvetica”,Font.PLAIN, 24);
Font getFont() { if (!chinese) return HELVETICA; else return new ChineseFont(); }
43 TS-754, Correct and Efficient Synchronization of Java Threads
Using Static Singletons
static final Font HELVETICA = new Font(“Helvetica”,Font.PLAIN,24);
static class CFSingleton{ static final Font CHINESE = new ChineseFont(...); } Font getFont() { if (!chinese) return HELVETICA; else return CFSingleton.CHINESE; }
44 TS-754, Correct and Efficient Synchronization of Java Threads
Unsynchronized
Reads/Writes of References
- Beware of unsynchronized getX/setX
methods that return a reference
- Same problems as double check
- Doesn’t help to synchronize only setX private Color color; void setColor(int rgb) { color = new Color(rgb); } Color getColor() { return color; }
45 TS-754, Correct and Efficient Synchronization of Java Threads
Thread blinker = null; public void start() { blinker = new Thread(this); blinker.start(); } public void stop() { blinker = null;} public void run() { Thread me = Thread.currentThread(); while (blinker == me) { try {Thread.currentThread().sleep(delay);} catch (InterruptedException e) {} repaint(); } }
Thread Termination in
Sun’s Demo Applets
unsynchronized access to blinker field
confusing but not wrong: sleep is a static method 46 TS-754, Correct and Efficient Synchronization of Java Threads
Problems
- Don’t assume another thread will see
your writes
- Just because you did them
- Calling sleep doesn’t guarantee you see
changes made while you slept
- Nothing to force thread that called stop to push change out of registers/cache
47 TS-754, Correct and Efficient Synchronization of Java Threads
Wrap-up
- Cost of synchronization operations
can be significant
- But cost of needed synchronization rarely is
- Thread interaction needs careful thought
- But not too clever
- Need for synchronization...
48 TS-754, Correct and Efficient Synchronization of Java Threads
Wrapup - Synchronization
- Communication between threads
- Requires both threads to synchronize
- Or communication through volatile fields
- Synchronizing everything
- Is rarely necessary
- Can be expensive (3%-20% overhead)
- May lead to deadlock
- May not provide enough synchronization