java- concurrent programming - synchronization (part 1)

27

Click here to load reader

Upload: riccardo-cardin

Post on 13-Apr-2017

1.355 views

Category:

Software


2 download

TRANSCRIPT

Page 1: Java- Concurrent programming - Synchronization (part 1)

CONCURRENT PROGRAMMINGSYNCHRONIZATION (PART 1)PROGRAMMAZIONE CONCORRENTE E DISTR.Università degli Studi di Padova

Dipartimento di Matematica

Corso di Laurea in Informatica, A.A. 2015 – [email protected]

Page 2: Java- Concurrent programming - Synchronization (part 1)

2Programmazione concorrente e distribuita

SUMMARY Introduction Thread-safety Race conditions Locking Locking pitfalls

Riccardo Cardin

Page 3: Java- Concurrent programming - Synchronization (part 1)

3Programmazione concorrente e distribuita

INTRODUCTION Threads can reduce development cost and

improve the performance applicationExploiting multiple processors

Improved throughput by utilizing available processorsSimplicity of modeling

Use every thread to do a specific task is simplier than using one thread to do them all

Simplified handling of asynchronous events Prevention of server’s stall while it is fulfilling a request

More reponsive user interfaces Use of different threads for GUI and event management

Event dispatch thread (EDT)

Riccardo Cardin

Page 4: Java- Concurrent programming - Synchronization (part 1)

4Programmazione concorrente e distribuita

INTRODUCTION Risks of threads

Safety hazards Without sufficient synchronization, the ordering of

operations in multiple threads is unpredictable

Riccardo Cardin

public class UnsafeSequence { private int value; /** Returns a unique value. */    public int getNext() { return value++; // Three operations: read, add and store    }}

With unlucky timing, two threads could call getNext and receive

the same value

Page 5: Java- Concurrent programming - Synchronization (part 1)

5Programmazione concorrente e distribuita

INTRODUCTION Risks of threads

Liveness hazards An activity gets into a state such that it is permanently unable

to make forward progress

Dining philosophers problem

Performance hazards Poor service time, responsiveness, throughput,resource consumption, or scalability Context switch is not cost free

Riccardo Cardin

If thread A is waiting for a resource that thread B holds exclusively, and B never releases it, A will wait forever.

Page 6: Java- Concurrent programming - Synchronization (part 1)

6Programmazione concorrente e distribuita

INTRODUCTION

Riccardo Cardin

Page 7: Java- Concurrent programming - Synchronization (part 1)

7Programmazione concorrente e distribuita

THREAD SAFETY Writing thread-safe code is about managing

access to shared and mutable state Object state is represented by its dataBy Shared, we mean that a variable could be

accessed by multiple threadsBy mutable, that its value could change

It is far easier to design a class to be thread-safe than to retrofit it later

Riccardo Cardin

Whenever more than a thread accesses a given state variable, and one of them might write to it, they all must coordinate their access to it using synchronization

-- Brian Goetz

Page 8: Java- Concurrent programming - Synchronization (part 1)

8Programmazione concorrente e distribuita

THREAD SAFETY There are three ways to fix a mutable shared

variableDon’t share the state variable across threadsMake the state variable immutableUse synchronization whenever accessing it

Object oriented techniques favor thread safetyEncapsulation ImmutabilityClear specification of invariants

Riccardo Cardin

Stateless objects are always thread-safe.-- Brian Goetz

Page 9: Java- Concurrent programming - Synchronization (part 1)

9Programmazione concorrente e distribuita

THREAD SAFETY

Riccardo Cardin

Page 10: Java- Concurrent programming - Synchronization (part 1)

10Programmazione concorrente e distribuita

RACE CONDITIONS

Race conditionsThe correctness of a computation depends on relative

timing of multiple threads at runtime

Atomicity A set of statements is not atomic if they are not executed in a

single, indivisible operation Read-modifiy-write Check-then-act

Riccardo Cardin

A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment.

-- Brian Goetz

Page 11: Java- Concurrent programming - Synchronization (part 1)

Programmazione concorrente e distribuita

RACE CONDITIONS Read-modify-write race condition

The value of value is read, then modified adding 1 and finally stored into value variable Among the execution of every statement, control flow could

be preempted by another thread

11Riccardo Cardin

public class UnsafeSequence { private int value; /** Returns a unique value. */    public int getNext() { value = value + 1; return value;    }}

read value value + 1 store value

Possible preemption

Page 12: Java- Concurrent programming - Synchronization (part 1)

12Programmazione concorrente e distribuita

RACE CONDITIONS Check-then-act race condition

Lazy initialization

The boolean expression depends on a value that is modified according to it

Riccardo Cardin

public class LazyInitRace { private ExpensiveObject instance = null; public ExpensiveObject getInstance() { // Check-then-act if (instance == null)         instance = new ExpensiveObject();        return instance; }}

check instance create object store instance

Possible preemption

Page 13: Java- Concurrent programming - Synchronization (part 1)

13Programmazione concorrente e distribuita

RACE CONDITIONS Compound actions

Sequences of operations that must be executed atomically in order to remain thread-safe. Read-modify-write and Check-then-act must always be

atomic to be thread-safeAtomicity is relative to operation that are executed

on shared state The java.util.concurrent.atomic package contains

atomic variable classes for effecting atomic state transitions

Riccardo Cardin

public class SafeSequence { private AtomicInteger value;    public int getNext() { return value.incrementAndGet(); // Atomic read-modify-write    }}

Page 14: Java- Concurrent programming - Synchronization (part 1)

14Programmazione concorrente e distribuita

RACE CONDITIONS

Riccardo Cardin

Page 15: Java- Concurrent programming - Synchronization (part 1)

15Programmazione concorrente e distribuita

SHARING STATE Writing correct concurrent programs is primarily

about managing access to shared, mutable state It’s all about memory visibility

We want to ensure that when a thread modifies the state of an object, other threads can actually see those changes

If shared state is represented by more than one variable, atomic classes are not useful

Riccardo Cardin

public class UnsafeCachedSequence { private AtomicInteger lastValue; private AtomicInteger value;    public int getNext() { // Invariant of the class is not satisfied anymore lastValue.set(value.get()); return value.incrementAndGet();    }}

Page 16: Java- Concurrent programming - Synchronization (part 1)

16Programmazione concorrente e distribuita

LOCKING To preserve state consistency, update related

state variable in a single atomic operation Java has a built-in locking mechanism for enforcing

atomicity: synchronized block

But, it is easier to understand the synchronized keyword after having seen locks in isolation...Riccardo Cardin

synchronized (lock) { // Access or modify shared state guarded by lock}

Object that will serve as lock

Block code to be guarded by the lock

Page 17: Java- Concurrent programming - Synchronization (part 1)

17Programmazione concorrente e distribuita

LOCKING Reentrant locking

Use a Lock to protect a code block

The construct guarantees that only one thread at time can enter the critical section Always release the lock in a finally block to prevents deadlocks The class ReentranctLock implements basic functionalities of a lock

Riccardo Cardin

myLock.lock(); // a ReentrantLock objecttry { // Operation in this block are executed atomically} finally { // make sure the lock is unlocked even if an // exceptions thrown myLock.unlock();}

Page 18: Java- Concurrent programming - Synchronization (part 1)

18Programmazione concorrente e distribuita

LOCKING Reentrant locking

The lock acts as mutual exclusion locksRiccardo Cardin

public class SafeCachedSequence { private Lock lock = new ReentrantLock(); private int lastValue; private int value;    public int getNext() { // Invariant of the class is now satisfied lock.lock(); try { lastValue = value; value = value + 1; int result = value; } finally { lock.unlock(); } return result;    }}

Now the invariant of the class is

guaranteed by the lock: value and lastValue will

always be updated in a consistent way

Page 19: Java- Concurrent programming - Synchronization (part 1)

19Programmazione concorrente e distribuita

LOCKING Reentrant locking

Riccardo Cardin

Thread 1 Thread 2

getNext getNext

Unsynchronized

Thread 1 Thread 2

getNext

getNext

Synchronized

Page 20: Java- Concurrent programming - Synchronization (part 1)

20Programmazione concorrente e distribuita

LOCKING Reentrant locking

Different threads have to synchronize using the same instance of the lock

It is called reetrant because a thread can repeatedly acquire a lock that it already owns The lock has a hold count that keeps track of the nested calls

to the lock method Prevents deadlocks wrt the subclass mechanism

Every object in Java (since 1.0) has an intrinsic lock The synchronized keyword on a method protects the

access to that method using this reference as lock object All method’s code is guarded

Riccardo Cardin

Page 21: Java- Concurrent programming - Synchronization (part 1)

21Programmazione concorrente e distribuita

LOCKING Intrinsic locking

To call the method, a thread must acquire the intrinsic object lock Static synchronized methods use the Class object as lock.

Riccardo Cardin

public synchronized void method() { // method body}

// ...is equivalent topublic void method() { this.intrinsicLock.lock(); try { // method body } finally { this.intrinsicLock.unlock(); }}

Page 22: Java- Concurrent programming - Synchronization (part 1)

22Programmazione concorrente e distribuita

LOCKING Intrinsic locking suffers of performance issues

Use synchronization by Lock objectOr synchronized block

It uses the reference to an object that will serve as lock

Riccardo Cardin

public class SafeCachedSequence { private Object lock = new Object(); private int lastValue; private int value;    public int getNext() { synchronized (lock) { lastValue = value; value = value + 1; int result = value; } return result;    }}

Page 23: Java- Concurrent programming - Synchronization (part 1)

23Programmazione concorrente e distribuita

LOCKING

Riccardo Cardin

Page 24: Java- Concurrent programming - Synchronization (part 1)

24Programmazione concorrente e distribuita

LOCKING PITFALLS All the accesses to a mutable shared variable

must be performed with the same lock heldNot only compound actions

Not all data needs to be guarded by a lockOnly mutable data

All the variables involved in the same invariant must be guarded by the same lock It is not sufficient to use intrinsic lock on every

method

Riccardo Cardin

// Not thread-safeif (!vector.contains(element))    vector.add(element);

Page 25: Java- Concurrent programming - Synchronization (part 1)

25Programmazione concorrente e distribuita

LOCKING PITFALLS Poor concurrency

Limits by the availability of processing resources, not by the structure of application itself CPU intensive and I/O operations must be outside

synchronized blocksAcquiring and releasing a lock has some overhead

Not break down synchronized blocks too far

Riccardo Cardin

There is frequently a tension between simplicity and performance. When implementing a synchronization policy, resist the temptation to prematurely sacrifice simplicity (potentially compromising safety) for the sake of performance.

-- Brian Goetz

Page 26: Java- Concurrent programming - Synchronization (part 1)

26Programmazione concorrente e distribuita

EXAMPLES

Riccardo Cardin

https://github.com/rcardin/pcd-snippets

Page 27: Java- Concurrent programming - Synchronization (part 1)

27Programmazione concorrente e distribuita

REFERENCES Chap. 1 «Introduction», Java Concurrency in Practice, Brian Goetz,

2006, Addison-Wesley Professional Chap. 2 «Thread Safety», Java Concurrency in Practice, Brian Goetz,

2006, Addison-Wesley Professional Chap. 3 «Sharing Objects», Java Concurrency in Practice, Brian

Goetz, 2006, Addison-Wesley Professional Dining philosophers problem https://

en.wikipedia.org/wiki/Dining_philosophers_problem Chap. 14 «Multithreading», Core Java Volume I - Fundamentals, Cay

Horstmann, Gary Cornell, 2012, Prentice Hall Intrinsic Locks and Synchronization https://

docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

Riccardo Cardin