Java Concurrency - Thread

With Java Concurrency, applications can achieve higher performance and better code design.

Concurrency vs. Parallelism

concurrent computing - tasks are executed in overlapping time period.

concurrent programming is different from parallel computing. parallel computing means multiple calculations are carried out simultaneously. Parallel computing is impossible in a single core processor because only one calculation can occur at any time.

An application can be concurrent but not parallel - application is running two tasks in overlapping time periods but not at the same time.

Thread

In an Operating system, a process can hold one or more threads. Threads exists within a process. Threads belonging to a process share memory and resources within the process. Threads are sometimes called light weight process.

For more information on Threads, see A gentle introduction to multithreading

MultiThreading Benefits

Increase Responsiveness - When one thread is blocked or stucked in a slow operation, Operating system can switch to execute another thread. For example, UI thread can continue execution while IO thread is working on the background to save documents.

Economy - Threads are much cheaper to create than process.

Scalability - Some tasks can be divided into subtasks and be executed by threads. This increase the efficiency of the application.

Creating a Thread

You can create a thread by creating Runnable Interface or extending Thread class. It is perferred to create a Thread from a Runnable Interface.

1
2
3
4
5
6
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " - Hello!");
}
}
1
2
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();

You can also specify thread name in the constructor.

1
2
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable, "MyRunnable-0").start();

In Java 8, you can pass Lambda to create the thread

1
2
3
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " - Hello!");
}).start();

Thread methods

start()
cause a thread to start execution. The most important method of Thread. This method is different from run() method. run() does not start a new thread. It just executes Runnable’s run() method.

getId()
returns the id of this thread

getName()
return the thread’s name

Thread.currentThread()
static method to get the currently executing thread object.

example to print current thread’s name

1
System.out.println(Thread.currentThread().getName());

Thread.sleep(long)
static method to cause the current thread to sleep for specified number of milliseconds.

getPriority()
return the thread’s priority

setpriority(int)
sets the priority of the thread. priority is an integer between constant Thread.MIN_PRIORITY(1) and Thread.MAX_PRIORITY(10). The default priority is 5.

getState()
Returns the thread’s state. see Enum Thread.State

dumpStack()
Prints a stack trace of the current thread to the standard error stream. Use this method for debugging purpose.

getStackTrace()
Returns an array of stack trace elements. Use this method for debugging purpose.

yield()
Hint to cause the current thread to yield its use of processor. The scheduler is free to ignore this hint. Use it to reproduce bugs due to race conditions.

join()
Waits for this thread to die. The calling thread goes into wating state. It waits for the referenced thread to terminate. join() method is useful for inter-thread synchronization.

join(long millis)
Waits at most millis milliseconds for this thread to die.

Thread States

Thread state is defined in Thread.State. A thread can be in one of the following states:

  • NEW - A thread that has not yet started is in this state.
  • RUNNABLE - A thread executing in the Java virtual machine is in this state.
  • BLOCKED - A thread that is blocked waiting for a monitor lock is in this state.
  • WAITING - A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
  • TIMED_WAITING - A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
  • TERMINATED - A thread that has exited is in this state.

For more info, see Life Cycle of a Thread in Java

Sleep

Thread.sleep static method cause the current thread to sleep.

1
2
3
4
5
6
7
public static void main(String[] args) throws InterruptedException {
System.out.println("cout down starts!");
for(int i = 5; i >= 0; i--) {
Thread.sleep(1000);
System.out.println(i);
}
}

Interrupt

An interrupt is an indication to a thread that it should stop what it is doing and do something else. It’s up to the programmer to decide exactly how a thread responds to an interrupt.

MyCountDownRunnable.java - when interrupted, stop execution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyCountDownRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " - cout down starts!");
for(int i = 5; i >= 0; i--) {
try {
Thread.sleep(1000);
System.out.println(i);
} catch (InterruptedException e) {
return; // when interrupted, stop execution and return
}
}
}
}

Interrupte a thread by calling interrupt method

1
2
3
4
5
6
7
8
public static void main(String[] args) throws InterruptedException {
Thread myThread = new Thread(new MyCountDownRunnable(), "myRunnable-0");
myThread.start();
myThread.join(2500);
if(myThread.isAlive()) {
myThread.interrupt();
}
}

Daemon Thread

A daemon thread does not prevent the JVM from exiting when the program finishes. You don’t need daemon thread most of the time.

  • When a new thread is created it inherits the daemon status of its parent.
  • When all user threads finish, the JVM halts, and any remaining daemon threads are abandoned.

isDaemon()
Tests if this thread is a daemon thread.

setDaemon(boolean)
sets the thread to be a daemon thread or a user thread.

Reference