Title: Multithreading: Synchronisation
1Multithreading Synchronisation
2Synchronization
- Under normal circumstances, the behaviour of two
or more threads executing concurrently is
asynchronous and not coordinated - We are not able to predict which threads will be
allocated CPU time at any given moment. - It is, however, often the case that we require
two or more threads to be coordinated. - Threads communicate primarily by sharing access
to fields and the objects reference fields refer
to. - One example two threads share a common resource,
with one thread reading from the file while
another thread writes to the file - This form of communication is extremely
efficient, but makes two kinds of errors
possible thread interference and memory
consistency errors.
3Producer/Consumer Model
Scenario What happens if the producer produces a
number and begins writing it to the queue and
before he gets the chance to finish writing, the
consumer comes along and consumes the partially
written number? Instant data corruption!!
4Thread Interference
- Interference happens when two operations, running
in different threads, but acting on the same
data, interleave. - This means that the two operations consist of
multiple steps, and the sequences of steps
overlap. - A simple example
class Counter private int c 0 public
void increment() c public void
decrement() c-- public int value()
return c
5Memory Consistency Errors
- Memory consistency errors occur when different
threads have inconsistent views of what should be
the same data - A scenario (1) variable c 0 (2) Thread A
calls increment() method to increments the
variable (3) shortly afterwards, thread B prints
out the value. - If the two statements had been executed in the
same thread, it would be safe to assume that the
value printed out would be "1". - But if the two statements are executed in
separate threads, the value printed out might
well be "0", because there's no guarantee that
thread A's change to counter will be visible to
thread B - The key to avoiding memory consistency errors is
understanding the happens-before relationship. - This relationship is simply a guarantee that
memory writes by one specific statement are
visible to another specific statement.
6Synchronizing Threads
- The Java language provides two basic
synchronization idioms - synchronized methods
- synchronized statements
- To make a method synchronized, simply add the
synchronized keyword to its declaration
class Counter private int c 0 public
synchronized void increment() c
public synchronized void decrement()
c-- public synchronized int value()
return c
7Synchronized Methods
- Making these methods synchronized has two
effects - It is not possible for two invocations of
synchronized methods on the same object to
interleave. - When one thread is executing a synchronized
method for an object, all other threads that
invoke synchronized methods for the same object
block (suspend execution) until the first thread
is done with the object. - When a synchronized method exits, it establishes
a happens-before relationship with any subsequent
invocation of a synchronized method for the same
object. - This guarantees that changes to the state of the
object are visible to all threads. - Question Can constructors be synchronised?
8Threads and Locks
- In Java, every object has an associated lock
- By default, an object is unlocked.
- When a method is declared synchronized, the
executing thread must grab the lock associated
with the object before it can continue. - When an object is locked by one thread, no other
thread can enter a synchronized method for that
object. - Upon completion of the method, the lock is
automatically released. - Recommendations
- Synchronized methods enable a simple strategy
for preventing thread interference and memory
consistency errors if an object is visible to
more than one thread, all reads or writes to that
object's variables are done through synchronized
methods.
9Deadlocks (1)
- Definition
- Deadlock describes a situation where two or more
threads are blocked forever, waiting for each
other. - Scenario
- Thread A wants to withdraw some money from a
account by calling the following synchronized
method
public synchronized void withdraw(double
amount) while (balance lt amount) //wait for
the balance to grow
- But how can we wait for the balance to grow?
- Other threads will call deposit method, but they
will simply be blocked until the withdraw method
exists. - The withdraw method doesnt exit until it has
funds available.
10Deadlocks (2)
- An illustration
- Building a directed graph
- whose vertices represent threads
- whose edges represent the "is-waiting-for"
relation. - If this graph contains a cycle, the system is
deadlocked.
Thread A
Waiting for
Waiting for
Thread B
Thread C
Waiting for
11Deadlocks(3)
- How to avoid deadlocks?
- You cant simply call sleep inside the
synchronised method - If a thread sleeps inside a synchronised method,
it still locks the object. - Wait/Notify protocol
- The wait method temporarily releases an object
lock and deactivates the current thread. - The wait method can throw an InterruptedException
- Propagates that exception because it has no way
of knowing what the thread that calls the
withdraw method wants to do if it is interrupted.
public synchronized void withdraw(double amount)
throws InterruptedException while (balance lt
amount) wait()
12Deadlocks (4)
- Notify/NotifyAll methods
- The wait method is meaningless without the use of
notify or notifyAll which allows code that is
waiting to be notified that it can wake up and
continue executing. - You can call the notify method whenever the state
of an object has changed in a way that might
benefit waiting threads - The notify/notifyAll method can only be called
from a thread that has locked the object - The call to notify/notifyAll must be in a
synchronized method.
public synchronized void deposit(double
amount) . notifyAll( )//unblock all waiting
threads
13High-level Synchronisation in Java (1)
- (Added in J2SE5.0 and Included in
java.util.concurrent package) - public class CyclicBarrier
- A synchronization aid that allows a set of
threads to all wait for each other to reach a
common barrier point. - The barrier is called cyclic because it can be
re-used after the waiting threads are released. - A barrier can be created in one of two ways. You
can create a barrier with a number of parties
(threads), or with a number of parties and a
barrier action. - A common example used to demonstrate barriers is
the splitting of a task into subtasks or
segments, such that each subtask or segment can
be executed separately.
14High-level Synchronisation in Java (2)
- public class CountDownLatch
- A synchronization aid that allows one or more
threads to wait until a set of operations being
performed in other threads completes. - A CountDownLatch is initialized with a given
count. - The await methods block until the current count
reaches zero - after which all waiting threads are released
- any subsequent invocations of await return
immediately - Invocations of the countDown() method-Â Decrements
the count of the latch - This is a one-shot phenomenon -- the count cannot
be reset. If you need a version that resets the
count, consider using a CyclicBarrier.
15High-level Synchronisation in Java (3)
- public class ExchangerltVgt
- A synchronization point at which two threads can
exchange objects. - Each thread presents some object on entry to the
exchange method, and receives the object
presented by the other thread on return. - An Exchanger is often used when you have two
threads, one consuming a resource, and the other
producing it. - When the buffer used by the producer is full,
the producer waits for the consumer. - When the buffer used by the consumer is empty,
the consumer waits for the producer. - After both waits happen, the two threads swap
buffers. This works well when you know more items
will be produced. Otherwise, items will sit
waiting for a full buffer before swapping
buffers.
16QA
1. Why are there separate wait and sleep methods?
2. What will happen when you attempt to compile
and run the following code? public class
TestThread extends Thread public static void
main(String argv) TestThread
b new TestThread() b.run()
public void start()
for (int i 0 i lt10 i)
System.out.println("Value of i "
i)
17Resources
- Tutorials on concurrency programming
(http//java.sun.com/docs/books/tutorial/essential
/concurrency/) - Concurrent Programming in Java Design
Principles and Pattern (2nd Edition) by Doug Lea.
- Java Threads by Scott Oaks and Henry Wong