Concurrency : Threads Basics

Concurrency is the ability to run several programs or several parts of a program in parallel. In concurrent programming, there are two basic units of execution: processes and threads. It’s becoming more and more common for computer systems to have multiple processors or processors with multiple execution cores. This greatly enhances a system’s capacity for concurrent execution of processes and threads — but concurrency is possible even on simple systems, without multiple processors or execution cores.

Processes – A process has a self-contained execution environment,  each process has its own memory space. Processes are often seen as synonymous with programs or applications. However, what the user sees as a single application may in fact be a set of cooperating processes. A familiar example is running the spreadsheet program while also working with the word processor.

Threads – Threads are sometimes called lightweight processes. Threads exist within a process — every process has at least one. Threads share the process’s resources, including memory and open files. A familiar example is a word processor that is printing and formatting text at the same time. A thread is an independent sequential path of execution within a program.

There are two basic strategies for using Thread objects to create a concurrent application.

  • To directly control thread creation and management, simply instantiate Thread each time the application needs to initiate an asynchronous task.
  • To abstract thread management from the rest of your application, pass the application’s tasks to an executor.

An application that creates an instance of Thread must provide the code that will run in that thread. There are two ways to do this:

  • Implementing the Runnable Interface
  • Extending the Thread Class

Implementing the Runnable Interface

  • A class implements the Runnable interface, providing the run() method that will be executed by the thread. An object of this class is a Runnable object.
  • An object of the Thread class is created by passing a Runnable object as an argument in the Thread constructor call. The Thread object now has a Runnable object that implements the run() method.
    Thread(Runnable threadTarget)
    Thread(Runnable threadTarget, String threadName)
  • The start() method is invoked on the Thread object created in the previous step. The start() method returns immediately after a thread has been spawned. In other words, the call to the start() method is asynchronous.

package mynotes.concurrency.basic;

class ImplementRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("Thread " + Thread.currentThread().getName()
+ " running " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

public class ThreadByRunnable {
public static void main(String[] args) {
System.out.println("Thread = " +Thread.currentThread().getName());
Thread t1 = new Thread(new ImplementRunnable(), "t1");
Thread t2 = new Thread(new ImplementRunnable(), "t2");
t1.start();
t2.start();
System.out.println("Thread = " +Thread.currentThread().getName());
}
}

Output : (The will most probably vary if you run again and again)


Thread = main
Thread = main
Thread t2 running 0
Thread t1 running 0
Thread t2 running 1
Thread t1 running 1
Thread t1 running 2
Thread t2 running 2

Extending the Thread Class

Extend Thread class , override run() method and start the thread by calling start() on the object of this class. In the following code I have provided a constructor so as to give my thread a name. Its not compulsory, you can create object using the default one.


package mynotes.concurrency.basic;

class ExtendThread extends Thread {

public ExtendThread(String name) {
super(name);
}

@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("Thread " + Thread.currentThread().getName()
+ " running " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

public class ThreadByExtending {

public static void main(String[] args) {

System.out.println("Thread = " + Thread.currentThread().getName());
ExtendThread t1 = new ExtendThread("t1");
ExtendThread t2 = new ExtendThread("t2");
t1.start();
t2.start();
System.out.println("Thread = " + Thread.currentThread().getName());

}

}

The output is more or less same as previous, changing on every run.
When creating threads, there are two reasons why implementing the Runnable interface may be preferable to extending the Thread class:

  • Extending the Thread class means that the subclass cannot extend any other class, whereas a class implementing the Runnable interface has this option.
  • A class might only be interested in being runnable and, therefore, inheriting the full overhead of the Thread class would be excessive.

Note

  • If we override the start method of thread, it will act as any other normal method. To start the thread there must be super.start() inside.
  • The thread class implements Runnable interface and is not abstract.
  • Once a thread has terminated, it cannot be started by calling the start() method again(throws an illeagalstateexception). A new thread must be created and started.

Volatile

When multiple threads using the same variable, each thread will have its own copy of the local cache for that variable. So, when it’s updating the value, it is actually updated in the local cache not in the main variable memory. The other thread which is using the same variable doesn’t know anything about the values changed by the another thread. To avoid this problem, if you declare a variable as volatile, then it will not be stored in the local cache. Whenever thread are updating the values, it is updated to the main memory. So, other threads can access the updated value. Let us see this by an example:


package mynotes.concurrency.basic;

import java.util.Scanner;

class InfiniteLoop extends Thread {

private boolean status = true;
@Override
public void run() {
while (status) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

public void shutdown() {
status = false;
}
}

public class VolatileTest {

public static void main(String[] args) {
InfiniteLoop t1 = new InfiniteLoop();
t1.start();
System.out.println("Hit return to stop....");
Scanner sc = new Scanner(System.in);
sc.nextLine();

t1.shutdown();

}

}

Here there are 2 threads, the main one and t1. Ideally this program should run infinitely  (The t1 loop) and should stop when Return key is pressed (main thread updates the boolean variable). This will be the behavior in most system. However, in some system or versions of java, the t1 thread might decide to cache the boolean variable and read it locally, so despite the main thread updates the variable the t1 thread never reads it, so the program runs infinitely. To solve this, we can add volatile keyword in the variable that will guarantee that the variable will never be cached by any thread.


private volatile boolean status = true;

Thread Priorities 

Priorities are integer values from 1 (lowest priority given by the constant Thread. MIN_PRIORITY) to 10 (highest priority given by the constant Thread.MAX_PRIORITY). The default priority is 5 (Thread.NORM_PRIORITY). A thread inherits the priority of its parent thread. The priority of a thread can be set using the setPriority() method and read using the getPriority() method, both of which are defined in the Thread class.The setPriority() method can be used to finetune the performance of the program, but
should not be relied upon for the correctness of the program.

Thread Scheduler

  •  Preemptive schedulingIf a thread with a higher priority than the current running thread moves to the Readytorun state, the current running thread can be preempted (moved to the Readytorun state) to let the higher priority thread execute. 
  •  TimeSliced or RoundRobin scheduling – A running thread is allowed to execute for a fixed length of time, after which it moves to the Readytorun state to await its turn to run again.

It should be emphasised that thread schedulers are implementation and platform dependent, therefore, how threads will be scheduled is unpredictable, at least from platform to platform.

Grab all the code from my GitHub repository.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: