From Lecture: Synchronization
Monitor
idea: object state guarded by its mutex
monitor is just a class, whose all public methods “synchronize,” which means you can’t access state without holding mutex
Principal: let short methods hold the mutex in case it doesn’t affect performance
1 | T1: add(elem) |
when elem
is added, it may not be seen in size. So add
should be written as synchronized add (T elem) {}
Locks & Deadlock
Lock is achieved by a mutex
deadlocks happen when all threads end up being blocked by a mutex
e.g.
1 | class a{ |
1 | T1: a.f() ---> b.g() |
Say we first go into T1, we acquire a; Then before going into b.g()
in T1, we acquire b.g()
in T2. Then we get into a deadlock cause we can’t get b.g()
in a.f()
nor vice versa.
That’s because we wrote a lock acquisition order in cycle
Solution:
no cycle
write an order in which to acquire mutex
e.g.
a<b
: can’t acquirea
afterb
(which makesb.g()
illegal)And then write a spec
/** Requires: lock level < a */
acquire mutex in the same order (T1: A,B; T2: A,B instead of T2: B,A)
Barriers
in scientific computation, there are many computations embarrassingly parallel
- span N threads and wait until they are all done
- updates before barrier will be seen by all threads after the barrier
1 | b = new CyclicBarrier(N); // N is the number of threads(without R/W sharing) |
Blocking Abstractions
How to build your own threads-blocking abstractions?
e.g.
1 | /** computes two threads seperately and then add them together*/ |
Condition Variables
- allow you to block things until some condition is true
- a condition variable is always associated with a mutex
- every Java object has its own condition variable, which ties to its own mutex
A notifyAll()
is sent whenever any of the conditions may become true; threads awakened by notifyAll()
then test to see if their particular condition has become true; otherwise, they go back to sleep.
1 | /** Effect: blocks thread and releases mutex, wait for some condition to become true |
To block until condition is true:
1 | public void run(){ |
while (!condition) wait();
is the most usual way to write a condition variable
wait()
: wait for some condition to be true, which is determined by other threads
notifyAll()
called after whatever some of the operations already done can probably wake some method up