non-blocking synchronization — what is it and why we (don't?) need it

67
Alexey Fyodorov Odnoklassniki @23derevo Non-blocking synchronization what is it and why we (don't?) need it

Upload: alexey-fyodorov

Post on 15-Apr-2017

642 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Non-blocking synchronization — what is it and why we (don't?) need it

AlexeyFyodorovOdnoklassniki@23derevo

Non-blockingsynchronizationwhatisitandwhywe(don't?)needit

Page 2: Non-blocking synchronization — what is it and why we (don't?) need it

Whatisthistalkabout?

Page 3: Non-blocking synchronization — what is it and why we (don't?) need it

3

Concurrency

Page 4: Non-blocking synchronization — what is it and why we (don't?) need it

Whoisthistalkfor?

Page 5: Non-blocking synchronization — what is it and why we (don't?) need it

5

For concurrency beginners

SorryPlease go to another room

Page 6: Non-blocking synchronization — what is it and why we (don't?) need it

6

For concurrency beginners

SorryPlease go to another room

For non-blocking programming beginners

A short introduction

For advanced concurrent programmers

We will talk about CAS/atomics implementation details!

For hipsters We will cover internet hype!Immutable vs. Mutable

Page 7: Non-blocking synchronization — what is it and why we (don't?) need it

Intro.Locking

Page 8: Non-blocking synchronization — what is it and why we (don't?) need it

8

Page 9: Non-blocking synchronization — what is it and why we (don't?) need it

9

Main Models

Shared Memory Messaging

write + read send + onReceive

Similar to how we program it Similar to how a real hardware works

Distributed ProgrammingConcurrent Programming

Page 10: Non-blocking synchronization — what is it and why we (don't?) need it

10

Advantages of Parallelism

Resource utilization

Async handling

Simplicity

Utilization of several cores/CPUs

aka PERFORMANCE

Complexity goes to magic frameworks• ArrayBlockingQueue• ConcurrentHashMap• Akka

Responsible services, Responsible UI

Page 11: Non-blocking synchronization — what is it and why we (don't?) need it

11Lock lock = new ReentrantLock()

Lock lock = new ReentrantLock(true)

Page 12: Non-blocking synchronization — what is it and why we (don't?) need it

12Fairness

Lock lock = new ReentrantLock(true)

Page 13: Non-blocking synchronization — what is it and why we (don't?) need it

13

Locking in Java

Old Schoolwait()notify()notifyAll()

synchronized {doSomething();

}

public synchronized foo() {doSomethingElse();

} Lock lock = new ReentrantLock();try {

lock.lock();doSomething();

} finally {lock.unlock();

} Since Java 5

IntheLanguage IntheStandardLibrary(JDK)

java.util.concurrent.*java.util.concurrent.atomic.*

Page 14: Non-blocking synchronization — what is it and why we (don't?) need it

14

Counter

public interface Counter {

long get();

void increment();

}

Page 15: Non-blocking synchronization — what is it and why we (don't?) need it

15

Simple Counter

public interface Counter {

long get();

void increment();

}

public class SimpleCounter implements Counter {

long value = 0;

public long get() {return value;

}

public void increment() {value++;

}

}

Page 16: Non-blocking synchronization — what is it and why we (don't?) need it

16

Volatile Counter

public class VolatileCounter implements Counter {

volatile long value = 0;

public long get() {return value;

}

public void increment() {value++;

}

}

public interface Counter {

long get();

void increment();

}

Page 17: Non-blocking synchronization — what is it and why we (don't?) need it

17

Synchronized Counter

public class SynchronizedCounter implements Counter {

long value = 0;

public synchronized long get() {return value;

}

public synchronized void increment() {value++;

}

}

public interface Counter {

long get();

void increment();

}

Page 18: Non-blocking synchronization — what is it and why we (don't?) need it

18

Disadvantages of Locking

• Deadlocks• Priority Inversion• Reliability - What will happen if lock owner die?

• Performance- Scheduler can push lock owner out- No parallelism inside a critical section!

Page 19: Non-blocking synchronization — what is it and why we (don't?) need it

19

Amdahl’s Law

α non-parallelizable part of the computation

1-α parallelizable part of the computation

p number of threads

Sp="

α#%&α'

Page 20: Non-blocking synchronization — what is it and why we (don't?) need it

Weneedsomethingelse!

Page 21: Non-blocking synchronization — what is it and why we (don't?) need it

WelcometoNon-blockingSynchronization

Page 22: Non-blocking synchronization — what is it and why we (don't?) need it

22

If-Modify-Write

volatile int value = 0;

if (value == 0) {value = 42;

}

NoAtomicityintermsofJMM

Page 23: Non-blocking synchronization — what is it and why we (don't?) need it

23

Compare and Swap

int value = 0;

synchronized (...) {if (value == 0) {

value = 42;}

}

Page 24: Non-blocking synchronization — what is it and why we (don't?) need it

24

Compare and Swap

int value = 0;

i.compareAndSet(0, 42);

Page 25: Non-blocking synchronization — what is it and why we (don't?) need it

25

CAS Semantics

public class PseudoCAS {

private long value;

public synchronized long get() {return value;

}

public synchronized long compareAndSwap(long expectedValue, long newValue) {long oldValue = value;if (oldValue == expectedValue) {

value = newValue;}return oldValue;

}

public synchronized boolean compareAndSet(long expectedValue, long newValue) {return expectedValue == compareAndSwap(expectedValue, newValue);

}

}

Page 26: Non-blocking synchronization — what is it and why we (don't?) need it

26

Pseudo-CAS Counter

public class PseudoCasLoopCounter implements Counter {

private PseudoCAS value = new PseudoCAS();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}

}

public interface Counter {

long get();

void increment();

}

Page 27: Non-blocking synchronization — what is it and why we (don't?) need it

27

Pseudo-CAS Counter

public class PseudoCasLoopCounter implements Counter {

private PseudoCAS value = new PseudoCAS();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}

}

public interface Counter {

long get();

void increment();

}

Page 28: Non-blocking synchronization — what is it and why we (don't?) need it

CASin Java

Page 29: Non-blocking synchronization — what is it and why we (don't?) need it

29

CAS in Java

Since Java 5, JSR166

java.util.concurrent.atomic

• Scalars• Field updaters• Arrays• Compound variables• Accumulators/Adders

since Java 8

Page 30: Non-blocking synchronization — what is it and why we (don't?) need it

30

Scalars

• AtomicBoolean

• AtomicInteger

• AtomicLong

• AtomicReference

Page 31: Non-blocking synchronization — what is it and why we (don't?) need it

31

Scalars

• AtomicBoolean

• AtomicInteger

• AtomicLong

• AtomicReference

Page 32: Non-blocking synchronization — what is it and why we (don't?) need it

32

• boolean compareAndSet(long expect, long update)

• long addAndGet(long delta)

• long getAndAdd(long delta)

• long getAndDecrement()• long getAndIncrement()• long incrementAndGet()• …

AtomicLong

Page 33: Non-blocking synchronization — what is it and why we (don't?) need it

33

• boolean compareAndSet(long expect, long update)

• long addAndGet(long delta)

• long getAndAdd(long delta)

• long getAndDecrement()• long getAndIncrement()• long incrementAndGet()• …

AtomicLong

Page 34: Non-blocking synchronization — what is it and why we (don't?) need it

34

CAS Counter

public interface Counter {

long get();

void increment();

}

public class CasLoopCounter implements Counter {

private AtomicLong value = new AtomicLong();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}

}

Page 35: Non-blocking synchronization — what is it and why we (don't?) need it

35

Compare and Swap — Hardware Support

compare-and-swapCAS

load-link / store-conditionalLL/SC

cmpxchg

ldrex/strex lwarx/stwcx

Page 36: Non-blocking synchronization — what is it and why we (don't?) need it

36

CAS Disadvantages

ContendedCAS —> tonsofuseless CPUcycles

do {v = value.get();

} while (value.compareAndSet(v, v + 1));

Writing fastandcorrectCASalgorithmsrequiresanexpertise

Page 37: Non-blocking synchronization — what is it and why we (don't?) need it

37

• boolean compareAndSet(long expect, long update)

• long addAndGet(long delta)

• long getAndAdd(long delta)

• long getAndDecrement()• long getAndIncrement()• long incrementAndGet()• …

AtomicLong

Page 38: Non-blocking synchronization — what is it and why we (don't?) need it

38

Get-and-Add Counter

public interface Counter {

long get();

void increment();

}

public class CasLoopCounter implements Counter {

private AtomicLong value = new AtomicLong();

public long get() {return value.get();

}

public void increment() {value.getAndAdd(1);

}

}

Page 39: Non-blocking synchronization — what is it and why we (don't?) need it

3939

atomicLong.getAndAdd(5)

JDK7u95 JDK8u74

83

46

15 11

132105

45 43

1 2 3 4

ops/μs

threads

Page 40: Non-blocking synchronization — what is it and why we (don't?) need it

4040

atomicLong.getAndAdd(5)

JDK7u95 JDK8u74

83

46

15 11

132105

45 43

1 2 3 4

ops/μs

threads

Page 41: Non-blocking synchronization — what is it and why we (don't?) need it

4141

atomicLong.getAndAdd(5)

lock addq $0x5,0x10(%rbp))loop:mov 0x10(%rbx),%raxmov %rax,%r11add $0x5,%r11lock cmpxchg %r11,0x10(%rbx)sete %r11bmovzbl %r11b,%r11dtest %r10d,%r10dje loop

JDK7u95-XX:+PrintAssembly JDK8u74-XX:+PrintAssembly

83

46

15 11

132105

45 43

1 2 3 4

ops/μs

threads

Page 42: Non-blocking synchronization — what is it and why we (don't?) need it

42

AtomicLong.getAndAdd() — JDK 7

cmpxchg

Page 43: Non-blocking synchronization — what is it and why we (don't?) need it

43

AtomicLong.getAndAdd() — JDK 8

lock addqJVMIntrinsic

Page 44: Non-blocking synchronization — what is it and why we (don't?) need it

44

Multivariable Invariant

Page 45: Non-blocking synchronization — what is it and why we (don't?) need it

45

Multivariable Invariant

Page 46: Non-blocking synchronization — what is it and why we (don't?) need it

46

Field Updaters

• AtomicIntegerFieldUpdater- Reflection-based updater for volatile int

• AtomicLongFieldUpdater- Reflection-based updater for volatile long

• AtomicReferenceFieldUpdater- Reflection-based updater for volatile object

Page 47: Non-blocking synchronization — what is it and why we (don't?) need it

47

AtomicLongFieldUpdater

long addAndGet(T obj, long delta)

boolean compareAndSet(T obj, long exp, long upd)

long getAndAdd(T obj, long delta)

long incrementAndGet(T obj)

Page 48: Non-blocking synchronization — what is it and why we (don't?) need it

48

Volatile Counter

public class VolatileCounter implements Counter {

volatile long value = 0;

public long get() {return value;

}

public void increment() {value++;

}

}

public interface Counter {

long get();

void increment();

}

Page 49: Non-blocking synchronization — what is it and why we (don't?) need it

49

AtomicLongFieldUpdater-based Counter

public class AFUCounter implements Counter {

private final VolatileCounter counter = new VolatileCounter();

AtomicLongFieldUpdater<VolatileCounter> updater= AtomicLongFieldUpdater.newUpdater(VolatileCounter.class, "value");

public AFUCounter() throws NoSuchFieldException {Field field = VolatileCounter.class.getDeclaredField("value");field.setAccessible(true);

}

public long get() {return updater.get(counter);

}

public void increment() {updater.addAndGet(counter, 1);

}

}

Page 50: Non-blocking synchronization — what is it and why we (don't?) need it

50

AtomicLongFieldUpdater

Page 51: Non-blocking synchronization — what is it and why we (don't?) need it

51

AtomicLongFieldUpdater

Page 52: Non-blocking synchronization — what is it and why we (don't?) need it

52

AtomicArrays

AtomicIntegerArray

AtomicLongArray

AtomicReferenceArray

• long addAndGet(int i, long delta)

• long getAndAdd(int i, long delta)

• boolean compareAndSet(int i, long exp, long upd)

• long incrementAndGet(int i)

• …

Page 53: Non-blocking synchronization — what is it and why we (don't?) need it

53

Compound Variables

AtomicMarkableReferenceV сompareAndSet( V expectedRef, V newRef, boolean expectedMark, boolean newMark)

AtomicStampedReferenceboolean compareAndSet( V expectedRef, V newRef, int expectedStamp, int newStamp)

Page 54: Non-blocking synchronization — what is it and why we (don't?) need it

54

Accumulators

• DoubleAccumulator

• DoubleAdder

• LongAccumulator

• LongAdder

• (Striped64)

• void accumulate(long x)

• long get()

• long getThenReset()

• void reset()

Page 55: Non-blocking synchronization — what is it and why we (don't?) need it

55

Non-blocking Guarantees

Wait-Free Per-thread progress is guaranteed

Lock-Free Overall progress is guaranteed

Obstruction-Free Overall progress is guaranteed if threads don’t interfere with each other

Page 56: Non-blocking synchronization — what is it and why we (don't?) need it

56

AtomicLong-based Counter

public interface Counter {

long get();

void increment();

}

public class CasCounter implements Counter {

private AtomicLong value = new AtomicLong();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}

}

Anyguarantees?A. Wait-FreeB. Lock-FreeC. Obstruction-FreeD. Noguarantees

Page 57: Non-blocking synchronization — what is it and why we (don't?) need it

57

AtomicLong-based Counter

public interface Counter {

long get();

void increment();

}

public class CasCounter implements Counter {

private AtomicLong value = new AtomicLong();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}

}

Anyguarantees?A. Wait-FreeB. Lock-FreeC. Obstruction-FreeD. Noguarantees

Page 58: Non-blocking synchronization — what is it and why we (don't?) need it

58

AtomicLong-based Counter

public interface Counter {

long get();

void increment();

}

public class CasCounter implements Counter {

private AtomicLong value = new AtomicLong();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}

}

Anyguaranteesonx64?A. Wait-FreeB. Lock-FreeC. Obstruction-FreeD. Noguarantees

Page 59: Non-blocking synchronization — what is it and why we (don't?) need it

59

AtomicLong-based Counter

public interface Counter {

long get();

void increment();

}

public class CasCounter implements Counter {

private AtomicLong value = new AtomicLong();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}

}

Anyguaranteesonx64?A. Wait-FreeB. Lock-FreeC. Obstruction-FreeD. Noguarantees

Page 60: Non-blocking synchronization — what is it and why we (don't?) need it

Non-blockingDataStructures

Page 61: Non-blocking synchronization — what is it and why we (don't?) need it

61

Non-blocking Stack

Page 62: Non-blocking synchronization — what is it and why we (don't?) need it

62

Non-blocking queue

Michael and Scott, 1996https://www.research.ibm.com/people/m/michael/podc-1996.pdf

Threads help each other

Page 63: Non-blocking synchronization — what is it and why we (don't?) need it

References

Page 64: Non-blocking synchronization — what is it and why we (don't?) need it

64

Books

Page 65: Non-blocking synchronization — what is it and why we (don't?) need it

65

Concurrency-interest

http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest

Doug Lee and Co

Page 66: Non-blocking synchronization — what is it and why we (don't?) need it

66

Q & A

Page 67: Non-blocking synchronization — what is it and why we (don't?) need it

67

Thank you!