(See also SAV07 Lecture 18.)
There are two ways to create threads in Java: subclassing the Thread class or using the Runnable interface:
The Thread is an encapsulation of the thread construction and gives a way of communicating with the thread as an entity. The Thread class is used to spawn the thread and can be used to start or pause the thread.
The Thread class has three main methods:
1. start() : This method is called by the user of this class to spawn the new thread. start() executes the run() method as the new thread. 2. run() : This is the code that is to be run in the separate thread. This method can do whatever any normal method can do, such as call methods of other objects, instantiate objects, etc. 3. sleep([milliseconds]) : Causes the thread to pause for the specified number of milliseconds.
To spawn a new thread using the Thread class:
1. Subclass the Thread class. 2. Override the run() method. 3. Instantiate the Thread object. 4. Call its start() method at the point where you want to spawn the new thread.
The Runnable interface specifies only one method, which takes no parameters:
public void run();
This method effectively replaces the run() method of the Thread class and frees the programmer from the constraints of having to subclass Thread.
A Thread object must still be made, as its start() method is still needed. To spawn a thread using the Runnable interface:
1. Have the desired class implement the Runnable interface. 2. Implement the run() method. 3. Where needed, instantiate a Thread object using the Thread(Runnable target) or one of the other constructors that takes a Runnable target. 4. Call the Thread object's start() method at the point where you want to spawn the new thread.
Synchronized statement: When this statement is used in front of a method declaration, it prevents multiple threads from simultaneously executing the method. If one thread is executing the method, then all other threads are “locked” out and wait for the first thread to finish before they get their turn.
A thread may read the value of a variable or change its value. If two or more concurrent threads act on a shared variable, there is a possibility that the actions on the variable will produce timing-dependent results. This dependence on timing is inherent in concurrent programming, producing one of the few places in the language where the result of executing a program is not determined solely by this specification.
Each thread has a working memory, in which it may keep copies of the values of variables from the main memory that is shared between all threads. To access a shared variable, a thread usually first obtains a lock and flushes its working memory. This guarantees that shared values will thereafter be loaded from the shared main memory to the threads working memory. When a thread unlocks a lock it guarantees the values it holds in its working memory will be written back to the main memory.
Reference
Java thread class documentation
Examples
Chord is a static race detection tool for Java to find serious and previously unknown concurrency bugs in programs.
Before: Increasing clock speeds ⇒ even sequential programs ran faster
Now: Increasing #CPU cores ⇒ only concurrent programs will run faster
Data race occurs when same location is accessed simultaneously without common lock held by more than one thread where at least one thread is writing.
Field f is race-free if:
Tools used:
Goldilocks is a lockset-based algorithm for precisely computing the happens-before relation and detecting data-races at runtime(dynamic race detection).
1. Vector clocks * precisely compute the happens-before relation * have significantly more overhead 2. Locksets * imprecise -> may generate false race warnings * efficient
The happens-before relation hb for δ is the smallest transitively-closed relation on the set {1,2,…,n} such that for any k and l, we have k hb l if 1 < = k < = l < = n and one of the following holds: