Download Notes on Threads - Organization, Programming, Language | CMSC 330 and more Study notes Programming Languages in PDF only on Docsity!
CMSC 330: Organization of
Programming Languages
Threads
Deadlock
• Deadlock occurs when no thread can run
because all threads are waiting for a lock
- (^) No thread running, so no thread can ever release a
lock to enable another thread to run
Thread 1
l.lock(); m.lock(); ... m.unlock(); l.unlock();
Lock l = new ReentrantLock(); Lock m = new ReentrantLock(); Thread 2
m.lock(); l.lock(); ... l.unlock(); m.unlock();
This code can
deadlock…
-- when will it work?
-- when will it
deadlock?
Wait Graphs
l T1 Thread T1 holds lock l
T2 m
Thread T2 attempting to
acquire lock m
Deadlock occurs when there is a cycle in the graph
Wait Graph Example
l T
T2 m
T1 holds lock on l
T2 holds lock on m
T1 is trying to acquire a lock on m
T2 is trying to acquire a lock on l
Solution: Use Finally
static Lock l = new ReentrantLock();
void f () throws Exception { l.lock(); try { FileInputStream f = new FileInputStream("file.txt"); // Do something with f f.close(); } finally { // This code executed no matter how we // exit the try block l.unlock(); } }
Synchronized
• This pattern is really common
- (^) Acquire lock, do something, release lock under any
circumstances after we’re done
- (^) Even if exception was raised etc.
• Java has a language construct for this
- (^) synchronized (obj) { body }
- (^) Every Java object has an implicit associated lock
- (^) Obtains the lock associated with obj
- (^) Executes body
- (^) Release lock when scope is exited
- (^) Even in cases of exception or method return
Discussion
• An object and its associated lock are different!
- (^) Holding the lock on an object does not affect what
you can do with that object in any way
- (^) Ex: synchronized(o) { ... } // acquires lock named o o.f (); // someone else can call o’s methods o.x = 3; // someone else can read and write o’s fields
object o
o’s lock
Example: Synchronizing on this
• Does this program have a data race?
- (^) No, both threads acquire locks on the same object
before they access shared data
class C { int cnt;
void inc() { synchronized (this) { cnt++; } } }
Thread 1 c.inc();
Thread 2 c.inc();
C c = new C();
Example: Synchronizing on this (cont’d)
• Does this program have a data race?
- (^) No, threads acquire different locks, but they write to
different objects, so that’s ok
class C { int cnt;
void inc() { synchronized (this) { cnt++; } } }
Thread 1 c1.inc();
Thread 2 c2.inc();
C c1 = new C(); C c2 = new C();
Synchronized Methods
• Marking method as synchronized same as
synchronizing on this in body of the method
- (^) The following two programs are the same
class C { int cnt;
void inc() { synchronized (this) { cnt++; } } }
class C { int cnt;
synchronized void inc(){ cnt++; } }
Synchronized Static Methods
• Warning: Static methods lock class object
- (^) There’s no this object to lock
class C { static int cnt;
void inc() { synchronized (this) { cnt++; } }
static synchronized void dec() { cnt--; } }
Thread 1 c.inc();
Thread 2 C.dec();
C c = new C();
What can be synchronized?
• code blocks
• methods
- (^) subclasses do not inherit synchronized keyword
- (^) interface methods cannot be declared synchronized
• NOT fields
- (^) but you could write synchronized accessor methods
• NOT constructors
- (^) but you could include synchronized code blocks
• objects in an array
Thread Lifecycle
• While a thread executes, it goes through a
number of different phases
- (^) New : created but not yet started
- (^) Runnable : can run on a free CPU
- (^) Running : currently executing on a CPU
- (^) Blocked : waiting for I/O or on a lock
- (^) Sleeping : paused for a user-specified interval
- (^) Terminated : completed
Which Thread to Run Next?
• Look at all runnable threads
- (^) A good choice to run is one that just became
unblocked because
- (^) A lock was released
- (^) I/O became available
- (^) It finished sleeping, etc.
• Pick a thread and start running it
- (^) Can try to influence this with setPriority(int)
- (^) Higher-priority threads get preference
- (^) But you probably don’t need to do this