ilJUG Java 8 Launch Event #2 Stamped Locks
!
Haim Yadid - Performize-IT
About Me: Haim Yadid
•21 Years of SW development experience •Performance Expert •Consulting R&D Groups •Training: Java Performance Optimization •Organizing : ILJUG
IL JUG
•Israeli Java User Group •Reborn at 1/14 •Meetup : http://www.meetup.com/IL-JUG •G+: https://plus.google.com/u/0/communities/110138558454900054301
•Twitter: @il_jug
Synchronization
Synchronized keyword was introduced to the java language from the beginning Acquire the lock on any java object
By default locking object instance on instance methods Locking the class on static methods
© Copyright Performize IT LTD.
synchronized void foo(){ do something(); }
private Object x = new Object(); void bar() { synchronized (x) { do something; } }
Volatile keyword
Insures access atomicity Visibility and order
© Copyright Performize-IT LTD.CPU Profiling: Lock Contention
private volatile long counter;
public long getCounter() { return counter; }
public void increment(long amount){ ++counter; }
Contention
•Two threads are considered to be contended when they try to access same lock on the same time •Locking mechanism behaves differently under contention • Contention degrades performance dramatically
ReentrantLock
Introduced in Java5 Part of the java.util.concurrent package Enhanced flexibility In Java 5 had better performance (fixed by now)
© Copyright Performize IT LTD.
private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } }
ReadWriteLock
Introduced in Java5 Part of the java.util.concurrent package Two locks work together inside the same lock Any amount of readers can work concurrently Write locks are taken exclusively
© Copyright Performize IT LTD.
public void increment(long amount) { try { rwlock.writeLock().lock(); counter+=amount; } finally { rwlock.writeLock().unlock(); } }
public long getCounter() { try { rwlock.readLock().lock(); return counter; } finally { rwlock.readLock().unlock(); } }
Introduce Fairness
Reentrant locks can work in fair and non fair mode. Fair mode means that requests to the lock object are accepted by the order they have been received. Prevents starvation Predictable latency Much slower
© Copyright Performize IT LTD.
private final ReentrantLock lock = new ReentrantLock(true);
Deadlocks
A Deadlock is a severe problem in a Java program It is a non recoverable situation requires JVM restart A cycle of locks held by different thread where each one is waiting another thread to release a lock.
© Copyright Performize-IT LTD.CPU Profiling: Concurrency problems
Thread A
Lock X
Wait on Y
Thread B
Lock Y
Wait on X
tryLock
With synchronized keyword you are not able to control how much to wait Reetrantlock introduces
tryLock() – If lock already taken return false tryLock(timeout,timeunit) – Waits for a certain amount of time
Can be a solution to deadlocks
© Copyright Performize-IT LTD.CPU Profiling: Lock Contention
CAS
Other approaches use low level construct such as compare and swap Faster than synchronized Limited in functionality Can be used to develop complicated mechanism
© Copyright Performize-IT LTD.CPU Profiling: Lock Contention
private final AtomicLong atomic = new AtomicLong();
public void increment(long amount) { atomic.addAndGet(amount); }
public long getCounter() { return atomic.get(); }
J8 - LongAdder
Added to J8 - should be faster on multi threaded environment compared to AtomicLong Also a version for DoubleAdder
© Copyright Performize-IT LTD.CPU Profiling: Lock Contention
LongAdder adder = new LongAdder();
public void increment(long amount) { adder.add(amount); }
public long getCounter() { return adder.longValue(); }
J8 - LongAdder Benchmark
Taken from http://minddotout.wordpress.com/2013/05/11/java-8-concurrency-longadder/
© Copyright Performize-IT LTD.CPU Profiling: Lock Contention
Stamped Locks
Pessimistic
Can work the same as read write lock Assumes contention Get a stamp from
© Copyright Performize IT LTD.
long stamp = rwlock.writeLock(); try { counter+= amount; } finally { rwlock.unlockWrite(stamp); }
long stamp = rwlock.readLock(); try { result = counter; } finally { rwlock.unlockRead(stamp); } return result;
Optimistic Approach
Optimistic Mechanism Try perform read if disturbed retry
© Copyright Performize-IT LTD.CPU Profiling: Lock Contention
private StampedLock rwlock = new StampedLock(); !long stamp = rwlock.tryOptimisticRead(); result = counter; !if (rwlock.validate(stamp)) { return result; }
Retry
If failed one can retry
© Copyright Performize-IT LTD.CPU Profiling: Lock Contention
for (i=0;i<maxRetries;i++) { long stamp = rwlock.tryOptimisticRead(); result = counter; if (rwlock.validate(stamp)) { return result; } }
Micro Benchmark
Original version developed by Tal Weiss (Takipi) https://github.com/takipi/counters-benchmark.git
Modified benchmark here https://github.com/lifey/counters-benchmark.git
The two benchmarks are very different and yield different results ( mine is better :) )
© Copyright Performize IT LTD.
Disclaimer
Beware of micro benchmarks. Benchmarks can be flawed. Including this one Under different conditions they may behave differently They prove nothing for real life application Benchmark your real life applications as well Saying that benchmark contains:
Warmup Average on 10 iterations after warmup
© Copyright Performize IT LTD.
ReaderWriter
A class which with configurable probability either increases a counter Reads its value
A single iteration performs it for 200M times Number of threads is configurable
© Copyright Performize IT LTD.
ReaderWriter
© Copyright Performize IT LTD.
if ((innerCounter % modulo) != 0) { // read long count = counter.getCounter();! if (count > Main.TARGET_NUMBER) { Main.publish(System.currentTimeMillis()); break; } } else { // write counter.increment(modulo);}innerCounter++;
Different Implementations
Volatile - using volatile keyword Atomic - AtomicLong Adder - LongAdder Synchronized Stamped (0,1,3,5 optimistic attempts) RW lock Fair RW lock
© Copyright Performize IT LTD.
Results 1/2 writes - 1 thread
© Copyright Performize IT LTD.
0
1750
3500
5250
7000
Vola
tile
Ato
mic
Add
er
Sync
RWLo
ck
Stam
ped0
Stam
ped1
Stam
ped3
Stam
ped5
Results 1/2 writes
© Copyright Performize IT LTD.
Valu
e A
xis
0
20000
40000
60000
80000Vo
latil
e
Ato
mic
Add
er
Sync
RWLo
ck
Stam
ped0
Stam
ped1
Stam
ped3
Stam
ped5
1 2 3 4
Results (1/10 writes) - single thread
© Copyright Performize IT LTD.
0
2250
4500
6750
9000
Vola
tile
Ato
mic
Add
er
Sync
RWLo
ck
Stam
ped0
Stam
ped1
Stam
ped3
Stam
ped5
Results (1/10 writes)
© Copyright Performize IT LTD.
0
25000
50000
75000
100000
Vola
tile
Ato
mic
Add
er
Sync
RWLo
ck
Stam
ped0
Stam
ped1
Stam
ped3
Stam
ped5
Results 1/100 writes
© Copyright Performize IT LTD.
0
10000
20000
30000
40000
Vola
tile
Ato
mic
Add
er
Sync
RWLo
ck
Stam
ped0
Stam
ped1
Stam
ped3
Stam
ped5
Results 1/100 writes
© Copyright Performize IT LTD.
0
4000
8000
12000
16000
Vola
tile
Ato
mic
Add
er
Sync
Stam
ped1
Stam
ped3
Stam
ped5
Insights
RWlocks really suck under high contention. StampedLocks require at least one optimistic try. When update probability goes down more than one retry may be beneficial RWLock.tryLock is similar to lock Under low write rate StampedLock with retries can get close to atomic/volatile Fair locks are x100 slower than non fair locks under extreme cases
© Copyright Performize IT LTD.
Additional Reading - LongAddr
http://minddotout.wordpress.com/2013/05/11/java-8-concurrency-longadder/ http://blog.palominolabs.com/2014/02/10/java-8-performance-improvements-longadder-vs-atomiclong/ http://psy-lob-saw.blogspot.co.il/2013/05/using-jmh-to-benchmark-multi-threaded.html?m=1 http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/LongAdder.html
© Copyright Performize IT LTD.
Additional Reading - StampedLock
http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/StampedLock.html http://www.takipiblog.com/2014/05/30/java-8-stampedlocks-vs-readwritelocks-and-synchronized/ http://www.javaspecialists.eu/archive/Issue215.html
© Copyright Performize IT LTD.
Thanks + Q&A + Contact Me
© Copyright Performize-IT LTD.
http://il.linkedin.com/in/haimyadid
www.performize-it.com
blog.performize-it.com
https://github.com/lifey
@lifeyx