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
Volatile
Atomic
Adder
Sync
RWLock
Stamped0
Stamped1
Stamped3
Stamped5
Results 1/2 writes
© Copyright Performize IT LTD.
ValueAxis
0
20000
40000
60000
80000
Volatile
Atomic
Adder
Sync
RWLock
Stamped0
Stamped1
Stamped3
Stamped5
1 2 3 4
Results (1/10 writes) - single thread
© Copyright Performize IT LTD.
0
2250
4500
6750
9000
Volatile
Atomic
Adder
Sync
RWLock
Stamped0
Stamped1
Stamped3
Stamped5
Results (1/10 writes)
© Copyright Performize IT LTD.
0
25000
50000
75000
100000
Volatile
Atomic
Adder
Sync
RWLock
Stamped0
Stamped1
Stamped3
Stamped5
Results 1/100 writes
© Copyright Performize IT LTD.
0
10000
20000
30000
40000
Volatile
Atomic
Adder
Sync
RWLock
Stamped0
Stamped1
Stamped3
Stamped5
Results 1/100 writes
© Copyright Performize IT LTD.
0
4000
8000
12000
16000
Volatile
Atomic
Adder
Sync
Stamped1
Stamped3
Stamped5
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
lifey@performize-it.com
www.performize-it.com
blog.performize-it.com
https://github.com/lifey
@lifeyx

Java 8 - Stamped Lock

  • 1.
    ilJUG  Java  8  Launch  Event  #2   Stamped  Locks                                     ! Haim Yadid - Performize-IT
  • 2.
    About  Me:  Haim  Yadid •21 Years of SW development experience •Performance Expert •Consulting R&D Groups •Training: Java Performance Optimization •Organizing : ILJUG
  • 3.
    IL  JUG •Israeli JavaUser Group •Reborn at 1/14 •Meetup : http://www.meetup.com/IL-JUG •G+: https://plus.google.com/u/0/communities/110138558454900054301 •Twitter: @il_jug
  • 4.
    Synchronization Synchronized keyword wasintroduced 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; } }
  • 5.
    Volatile keyword Insures accessatomicity 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; }
  • 6.
    Contention •Two threads areconsidered to be contended when they try to access same lock on the same time •Locking mechanism behaves differently under contention • Contention degrades performance dramatically
  • 7.
    ReentrantLock Introduced in Java5 Partof 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() } }
  • 8.
    ReadWriteLock Introduced in Java5 Partof 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(); } }
  • 9.
    Introduce Fairness Reentrant lockscan 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);
  • 10.
    Deadlocks A Deadlock isa 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
  • 11.
    tryLock With synchronized keywordyou 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
  • 12.
    CAS Other approaches uselow 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(); }
  • 13.
    J8 - LongAdder Addedto 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(); }
  • 14.
    J8 - LongAdderBenchmark Taken from http://minddotout.wordpress.com/2013/05/11/ java-8-concurrency-longadder/ © Copyright Performize-IT LTD.CPU Profiling: Lock Contention
  • 15.
    Stamped  Locks                                
  • 16.
    Pessimistic Can work thesame 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;
  • 17.
    Optimistic Approach Optimistic Mechanism Tryperform 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; }
  • 18.
    Retry If failed onecan 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; } }
  • 19.
    Micro Benchmark Original versiondeveloped 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.
  • 20.
    Disclaimer Beware of microbenchmarks. 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.
  • 21.
    ReaderWriter A class whichwith 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.
  • 22.
    ReaderWriter © Copyright PerformizeIT 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++;
  • 23.
    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.
  • 24.
    Results 1/2 writes- 1 thread © Copyright Performize IT LTD. 0 1750 3500 5250 7000 Volatile Atomic Adder Sync RWLock Stamped0 Stamped1 Stamped3 Stamped5
  • 25.
    Results 1/2 writes ©Copyright Performize IT LTD. ValueAxis 0 20000 40000 60000 80000 Volatile Atomic Adder Sync RWLock Stamped0 Stamped1 Stamped3 Stamped5 1 2 3 4
  • 26.
    Results (1/10 writes)- single thread © Copyright Performize IT LTD. 0 2250 4500 6750 9000 Volatile Atomic Adder Sync RWLock Stamped0 Stamped1 Stamped3 Stamped5
  • 27.
    Results (1/10 writes) ©Copyright Performize IT LTD. 0 25000 50000 75000 100000 Volatile Atomic Adder Sync RWLock Stamped0 Stamped1 Stamped3 Stamped5
  • 28.
    Results 1/100 writes ©Copyright Performize IT LTD. 0 10000 20000 30000 40000 Volatile Atomic Adder Sync RWLock Stamped0 Stamped1 Stamped3 Stamped5
  • 29.
    Results 1/100 writes ©Copyright Performize IT LTD. 0 4000 8000 12000 16000 Volatile Atomic Adder Sync Stamped1 Stamped3 Stamped5
  • 30.
    Insights RWlocks really suckunder 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.
  • 31.
    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.
  • 32.
    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.
  • 34.
    Thanks + Q&A+ Contact Me © Copyright Performize-IT LTD. http://il.linkedin.com/in/haimyadid lifey@performize-it.com www.performize-it.com blog.performize-it.com https://github.com/lifey @lifeyx