SSC - Concurrency and Multi-threading
Java multithreading programming
-Synchronisation (I)
Shan He
School for Computational Science University of Birmingham
Outline of Topics
Review what we learned
Issues in multithreading
Issues in multithreading
Code Data resourcesOther
Register Stack
Single thread process
Code Data resourcesOther
Register Stack
Multithreaded process
Stack Stack Register Register Memory segmentsIssues in multithreading
Problems will arise when multiple threads access the shared resources:
I Q: How threads communicate/coordinate?
I A: Essentially by sharing the same memory space, e.g., access
to fields and the objects reference fields refer to.
I Efficient, but makes two kinds of errors possible:
I Thread interference
I Memory consistency errors
I Note: Critical section - a piece of code that accesses a shared
Thread interference
I Also called race conditions
I Errors are introduced when multiple threads access and try to
change the same resource, e.g., memory (variables, arrays, objects), system (databases) or file
I Let’s take a look a very simple example: adding/subtracting
some values from 0.
I We first define a Class Counter to do adding/subtracting
I Suppose we want to reference a Counter object from two
threads which add 1 and then subtract 1.
I We expect we should get the outputs of 0 from both threads,
Atomic operations
I Atomic operation: an action either happens completely, or it
doesn’t happen at all.
I Even for a simple add() method, there are three atomic
operations:
I Step 1: Load value from counter into a register
I Step 2: Add some value to the register
Thread interference
I Simple example: two threads try to increase an integer value
by 1 (and later both decrease the vaule by 1)
I The steps when it went wrong:
Thread 1 Thread 2 Integer value
0 read value to r1 ←− 0 read value to r2 ←− 0 increase value in r1 0 increase value in r2 0 write back −→ 1 write back −→ 1
I ←− Step 1: Load integer value to a register
Thread interference: danger and solution
I Please read and execute my code example for thread
interference.
I You might notice most of the time it runs perfectly well
I This kind of bug is particularly difficult to find and fix
I One solution: Synchronisation, that is enforcing exclusive
Memory consistency errors
I Memory consistency errors: different threads have inconsistent
views of the same data.
I Example: Suppose we have one int field:
int count = 0;
I counter is shared between two threads A and B
I Thread A increments counter: count++;
I Thread B simply prints out counter:
System.out.println(counter);
I The output might not be predictable.
I No guarantee that thread A’s change to counter will be visible
Memory consistency errors
I Memory consistency errors VS. thread interference
I Thread interference: happens when different threads are changing the same data
I Memory consistency errors: happens when different threads have different views of the same shared data.
I The causes of these errors are complex: we only need to know
how to avoid them
I Key for avoiding these errors: understanding the
happens-before relationship, also denoted as →
I a → b: event a should happen before event b, the result must reflect that no matter what order those events are in reality executed.
I A guarantee that memory written to by statement A is visible to statement B, that is, that statement A completes its write before statement B starts its read.
Ways of creating happens-before relationships for thrads
I For threads share the same data, we need to write code to
explicitly implement happens-before relationships, esp. for executing new threads
I In Java, we can use Thread.join()
I Please take a look at my Java example
Synchronisation in Java
I Three tools for Synchronization:
I Locks: the most common synchronization tool
I Volatile Variables: establishes a happens-before relationship to solve the memory consistency errors
I Atomic Operations: nonblocking synchronization, ensure an action either happens completely, or it doesn’t happen at all to solve the thread interference problem
I Two ways of using locks:
I Reentrant Locks, and
I Synchronized keyword
I Two ways of using Synchronized keyword in Java:
I Synchronized methods, and
I Synchronized statements/blocks
I Differences: simply put, synchronized methods are simpler but
less flexible
Mechanisms behind Java synchronisation: Intrinsic lock
I Synchronization is built around an internal entity known as
the intrinsic lock, or monitor lock, or simple lock.
I In Java, every object has an intrinsic lock associated with it
I Intrinsic lock does two things:
I enforcing exclusive access to an object’s state; and
I establishing happens-before relationships
I How it works:
I Thread A acquires the object’s intrinsic lock before accessing
the object’s field −→ exclusive access
I No other thread can acquire the same lock before Thread A releases the lock −→ happens-before relationships accessing
Mechanisms behind Java synchronisation: monitor
I An important concept in concurrent programming and
operating system
I Monitor: a synchronization mechanism that allows threads:
I to have mutual exclusion
I to have the ability to wait for a certain condition to become true
I to signal other threads that their condition has been met.
I A monitor can be formally defined as M = (m, c), where m is
intrinsic lock object and c a condition variable.
I Intrinsic lock m: ensures exclusive access and happens-before
relationships
I Condition c: ensures threads attempting an operation to wait
until some condition, e.g., job queue is not empty, is met
I A monitor is basically a container of threads that are waiting
Mechanisms behind Java synchronisation: monitor
Waiting room (waiting set) Meeting room
(monitor region)
Hallway (Entry set)
Bank (Monitor) A waiting thread An active thread If occupied, entre waiting set Step 3: Release Step 4: Acquire
Step 1: entre entry set Step 2: If not
occupied, occupy monitor region Step 5: release
and exit
Some scheduling: FIFO Some object with