Skip to main content

Java Threads

Java threads are objects like any other Java objects.There are two ways to specify what code the thread should execute. Each Thread object has a state.

Threads are either daemon or non-daemon. By default threads are non daemon. So java main thread is non-daemon. Daemon threads don't stop the JVM from ending. Garbage collection run on a daemon thread.

info

New - When a new thread is created, it is in the new state. (new Thread();)

Runnable - A thread that is ready to run is moved to runnable state. (t1.run();)

Blocked - When a thread is temporarily inactive, e.g. (require a lock)

Waiting - When a thread is temporarily inactive, e.g. (wait on a condition);

Timed Waiting - A thread lies in timed waiting state when it calls a method with a time out parameter. (Thread.sleep(1000);)

Terminated - A thread terminates because of either of the following reasons: Normally exits or interrupted.

***The first is to create a subclass of Thread and override the run() method. The run() method is what is executed by the thread after you call start(). ***

By creating a class that implements the java.lang.Runnable interface. A Java object that implements the Runnable interface can be executed by a Java Thread.

Thread States

*** Callables and Futures***

A Runnable encapsulates a task that runs asynchronously; you can think of it as an asynchronous method with no parameters and no return value. A Callable is similar to a Runnable, but it returns a value. The Callable interface is a parameterized type, with a single method call.

public interface Callable<V>
{
V call() throws Exception; // V is the type of the returned value.
}

A Future holds the result of an asynchronous computation. The Future interface has the following methods:

public interface Future<V>
{
V get() throws . . .;
V get(long timeout, TimeUnit unit) throws . . .;
void cancel(boolean mayInterrupt);
boolean isCancelled();
boolean isDone();
}

The FutureTask wrapper is a convenient mechanism for turning a Callable into both a Future and a Runnable—it implements both interfaces. For example:

Callable<Integer> myComputation = . . .;
FutureTask<Integer> task = new FutureTask<Integer>(myComputation);
Thread t = new Thread(task); // it's a Runnable
t.start();
...
Integer result = task.get(); // it's a Future

Fork-join Framework

The fork-join framework allows to break a certain task on several workers and then wait for the result to combine them. It leverages multi-processor machine’s capacity to great extent.

Fork - A process in which a task splits itself into smaller and independent sub-tasks which can be executed concurrently. Join - A process in which a task join all the results of sub-tasks once the subtasks have finished executing, otherwise it keeps waiting. Classes:

- ForkJoinPool - A special thread pool designed to work with fork-and-join task splitting.
- RecursiveTask<V> - RecursiveTask represents a task which returns a value.
- RecursiveAction - Just like RecursiveTask except it does not return a result
- ForkJoinTask<V> - Superclass of RecursiveTask and RecursiveAction. fork() and join() are methods defined in this class.

Problems with Threads

Thread interactions can cause problems. Problems include race conditions ,data races and cached variable problem.

=> Threads normally increase complexity and debugging application will become tough. => A race condition can occur when threads depends on relative timing by the schedular. => A data race occurs when two are more threads access the same memory location.

Synchronization

Synchronization in Java is the capability to control the access of multiple threads to any shared resource. Java Synchronization is better option where we want to allow only one thread to access the shared resource.

The synchronization is mainly used to

  • Prevent thread interference.
  • Prevent consistency problem.

Synchronization can be used to solve Race condition, data races and cached variable problems.Java supports synchronization to ensure threads can safely update shared variables.Synchronization can applied to method and block level and so that code is known as critical section. JVM supports synchronization via monitors.

Every java object is associated with monitor which is mutual exclusion construct that prevents multiple threads from concurrently execution in critical section. Before thread enters a critical section it must get lock on the monitor. If the monitor is already locked then the thread is blocked until the monitor unlocked.

When a thread locks a monitor in a multi core multi processor environment, the values of the shared variables that are stored in the main memory are read into the copies of these variables that are stored in the threads working memory , also known as local memory and cache memory.

This action ensures access to most recent values.When thread unlocks the monitor by leaving critical section, these values are then copied into the shared variables and written back to main memory which lets the next thread that enters the critical section access the most recent values of these variables.

Concurrency Utilities

=> Task scheduling frameworks such as executors( provide thread pool management)

=> Fork/Join framework (It is designed to officially run large number of tasks using a pool of worker threads

=> Concurrent collections( Several new collection classes including newQueue,Blocking Queue and blockingDequeue interfaces and high performance implementation of map,list and queue)

=> Atomic variables( Atomically manipulate single variables , primitive types or references provide the high performance methods.

=> Synchronizers ( General purpose synchronize classes facilitate coordinate between threads)

Thread Synchronization

Thread synchronization is the concurrent execution of two or more threads that share critical resources. Threads should be synchronized to avoid critical resource use conflicts. Otherwise, conflicts may arise when parallel-running threads attempt to modify a common variable at the same time.

In Java, two synchronization strategies are used to prevent thread interference and memory consistency errors:

Synchronized Method: Includes the synchronized keyword in its declaration. When a thread invokes a synchronized method, synchronized method automatically acquires the intrinsic lock for that method's object and releases it when the method returns, even if that return was caused by an uncaught exception.

Synchronized Statement: Declares a block of code to be synchronized. Unlike synchronized methods, synchronized statements should specify the objects that provide the intrinsic lock. These statements are useful for improving concurrency with fine-grained synchronization, as they enable the avoidance of unnecessary blocking.