Java provides a special thread-safety guarantee concerning immutable objects. (link)
When a field variable is declared volatile, it cannot also be declared final. However, this isn’t a problem because Java also lets you safely access a final field without the need for synchronization (link)
Because stopped has been marked volatile, each thread will access the main memory copy of this variable and not access a cached copy. (link)
Multithreaded applications face the additional liveness challenges of deadlock, livelock, and starvation: (link)
Two or more threads that access the same code sequence must acquire the same lock or there will be no synchronization. (link)
Suppose you specify the following code sequence: System.out.println(ID.getID()); The lock is associated with ID.class, the Class object associated with ID. If another thread called ID.getID() while this method was executing, the other thread would have to wait until the executing thread released the lock. (link)
This property of synchronization is known as mutual exclusion because each thread is mutually excluded from executing in a critical section when another thread is inside the critical section. For this reason, the lock that the thread acquires is often referred to as a mutex lock. (link)
Synchronization is a JVM feature that ensures that two or more concurrent threads don’t simultaneously execute a critical section, which is a code section that must be accessed in a serial (one thread at a time) manner. (link)
A race condition is often confused with a data race in which two or more threads (in a single application) access the same memory location concurrently, at least one of the accesses is for writing, and these threads don’t coordinate their accesses to that memory. (link)
Because there is no happens-before ordering (one action must precede another action) between thread 1’s write of parser and thread 2’s read of parser (because there is no coordinated access to parser), a data race has occurred. (link)
Although it might look like a single operation, expression counter++ is actually three separate operations: read counter’s value, add 1 to this value, and store the updated value in counter. (link)
Another type of race condition is read-modify-write, in which new state is derived from previous state. (link)
A race condition occurs when the correctness of a computation depends on the relative timing or interleaving of multiple threads by the scheduler. (link)
The code fragment is an example of a common type of race condition that’s known as check-then-act, in which a potentially stale observation is used to decide on what to do next. (link)
A daemon thread is a thread that acts as a helper to a nondaemon thread and dies automatically when the application’s last nondaemon thread dies so that the application can terminate. (link)
Two terms that are commonly encountered when exploring threads are parallelism and concurrency. According to Oracle’s “Multithreading Guide” (http://docs.oracle.com/cd/E19455-01/806-5257/6je9h032b/index.html), parallelism is “a condition that arises when at least two threads are executing simultaneously.” In contrast, concurrency is “a condition that exists when at least two threads are making progress. [It is a] more generalized form of parallelism that can include time-slicing as a form of virtual parallelism.” (link)
There are two ways to create a Runnable object. The first way is to create an anonymous class that implements Runnable, as follows: Runnable r = new Runnable() { @Override public void run() { // perform some work System.out.println("Hello from thread"); } }; Before Java 8, this was the only way to create a runnable. Java 8 introduced the lambda expression to more conveniently create a runnable: Runnable r = () -> System.out.println("Hello from thread"); (link)
These threads execute code sequences encapsulated in objects that are known as runnables. (link)
The concurrency utilities include executors as a high-level alternative to low-level thread expressions for executing runnable tasks. (link)
The concurrency utilities can be classified as executors, synchronizers, a locking framework, and more. (link)
Timer Framework (link)
Vikram: [Read later]
Each ThreadLocal instance describes a thread-local variable, which is a variable that provides a separate storage slot to each thread that accesses the variable. (link)
This problem is an example of the “time of check to time of use” (https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use) class of software bug. (link)
Using a ThreadGroup object, you can perform an operation on all contained Thread objects. (link)