In Java programming What is concurrency, parallelism, multi-threading ? [Everything you need to know]
![](/image/blogThumbTf0jcic8uQ.png)
Introduction
Humans can :
- - drive a car and talk at the same time
- - read a book or post and eat or have a coffee at the same time
- - cook and talk
- - etc.. you get the idea.
We can do multiple tasks at the same time, we are multitask species.
Nowadays computers also are multitasks machines, they can play music, when you are writing an article or you send a message using email while downloading a file from internet...etc...thanks to operating systems who help managing these task.
Back in the days computers didn't have operating system, they execute one program at a time and the program had access to all the machine's resources (ram, network, disk ) until the end of it's execution.
Now operating system manage programs execution by allocating cpu time to each program running, when time elapse the operating system has the power to stop the program and switch to another program.
Processes
The operating system run programs as processes, not the binary it self. A process is an instance of a program that is running and have cpu time, and access to other resources (network, files, socket, memory).
In java program we can manage a process using the process abstract class. To create a process we can use the ProcessBuilder class, it has a method start() to start a new process and return us an instance of Process class
For example on Ubuntu to spawn a new process in java :
/**
* ProcessExample
*/
public class ProcessExample {
public static void main(String[] args)
{
try {
// create a new process to run vscode on
ProcessBuilder builder = new ProcessBuilder("code");
Process vscodeProcess = builder.start();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
To compile and run :
// to compile
javac ProcessExample.java
// to run
java ProcessExample
We can manage the vscode app process with the vscodeProcess variable :
- - get process pid :
// get vscode app process pid
long vscodePid = vscodeProcess.pid();
// print the result
System.out.println("vscodeProcess pid : " + vscodePid);
- - destroy the process
// destroy the vscode app process after 10 sec
Thread.sleep(10000); // sleep 10 sec
vscodeProcess.destroyForcibly(); // destroyForcibly() method destroy the Process instance
- - get the exit value
// we can get the exit value of the process after destroyed
int vscodeExitValue = vscodeProcess.exitValue();
System.out.println("vscodeProcess exit value : " + vscodeExitValue);
Complete code :
/**
* ProcessExample
*/
public class ProcessExample {
public static void main(String[] args)
{
try {
// create a new process to run vscode on
ProcessBuilder builder = new ProcessBuilder("code");
Process vscodeProcess = builder.start();
// get vscode app process pid
long vscodePid = vscodeProcess.pid();
System.out.println("vscodeProcess pid : " + vscodePid);
// destroy the vscode app process after 10 sec
Thread.sleep(10000); // sleep 10 sec
vscodeProcess.destroyForcibly(); // destroyForcibly() method destroy the Process instance
// we can get the exit value of the process after destroyed
int vscodeExitValue = vscodeProcess.exitValue();
System.out.println("vscodeProcess exit value : " + vscodeExitValue);
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
Threads
In a process we can have multiple theads. Thread is stream of a program, it's the basic or smallest unit of sequence of instructions to which the operating system can allocate cpu time.
They are also called lightweight process, because all the threads share the same wide resource (memory space, file handles, network cpu time etc..) of the process in which they are running.
They are widely used :
- in GUI programs (throughout libraries such as awt package) : to enhance responsiveness for example.
- in web apps to handle multiple requests.
Threads have advantages and inconveniences :
- advantages :
- - improve performance of processes that can be split into multiple independent unit by running these unit concurrently.
- - Also on multiprocessor systems threads can exploit hardware parallelism by scheduling simultaneously multiple threads on multiple cpu
- inconveniences :
- - risk of race conditions : since threads within the same process share the same memory space, there is a risk that multiple threads try to access to the same data at the same time or even modify the same data.
- - base performance : in the case of process with multiple threads the context switches can waste significant time pausing one thread and activating another thread instead of running the actual code.
Create thread in Java
In java when you the JVM run a program, it start a default thread that run the entry point method (main method). After that you can create a thread by :
- 1 - extending the Thread class : This class can handle thread, so any class extending this Thread class become threadable.
- by extending this class you should override the run() method.
- Using this class : we have access to many methods we can call on the thread object.
- For example we can create and start a thread : in the main method we start the InnerThreadExample class that extend Thread class.
public class ThreadExample {
public static void main(String[] args)
{
// create thread object
InnerThreadExample iExample = new InnerThreadExample();
// start the thread
iExample.start();
}
}
/**
* InnerThreadExample ==> extend Thread Class
*/
class InnerThreadExample extends Thread{
// override the run method of Thread
public void run(){
System.out.println("Running InnerThreadExample thread...");
}
}
- 2 - implementing the Runnable interface : This is often the preferred method because, after implementing the Runnable interface we can still extend classes, and also it's more intuitive since we are trying to use the thread functionality , not extending.
- With this approche, to create a thread we :
- - create an object of type Runnable
- - pass that object to the thread class it selft.
- - then we use the thread class directly this time.
- For example a runnable object that print 10 time hello, world. The we pass that object to Thread that run it.
public class ThreadExample {
public static void main(String[] args)
{
// create thread with Runnable type
PrintHelloWorld pWorld = new PrintHelloWorld();
// create a thread that will use the runnable object
Thread pThread = new Thread(pWorld);
// start the thread
pThread.start();
}
}
/**
* PrintHelloWorld ==> implement runnable interface
*/
class PrintHelloWorld implements Runnable{
// override Runnable run method
public void run(){
print();
}
private void print(){
for(int i=0; i<10; i++){
System.out.println(i + " - Hello, world");
}
}
}
To interact with threads, in either met we can use : .
- - .start() method to start the thread :
// start the thread
pThread.start();
- - .isAlive() method to check if a method is still alive :
// check if the thread is still alive
System.out.println("thread is alive ? : " + pThread.isAlive());
- - .getState() method to get a thread state :
// get the thread state
State st = pThread.getState();
System.out.println(st.name());
- - and many more methods : .sleep(), .wait() etc... Check the doc for more.
Complete code is here :
import java.lang.Thread.State;
public class ThreadExample {
public static void main(String[] args)
{
// create thread object with Thread type
InnerThreadExample iExample = new InnerThreadExample();
// start the thread
iExample.start();
// create thread with Runnable type
PrintHelloWorld pWorld = new PrintHelloWorld();
// create a thread that will use the runnable object
Thread pThread = new Thread(pWorld);
// start the thread
pThread.start();
// get the thread state
State st = pThread.getState();
System.out.println(st.name());
// check if the thread is still alive
System.out.println("thread is alive ? : " + pThread.isAlive());
}
}
/**
* InnerThreadExample ==> extend Thread Class
*/
class InnerThreadExample extends Thread{
// override the run method of Thread
public void run(){
System.out.println("Running InnerThreadExample thread...");
}
}
/**
* PrintHelloWorld ==> implement runnable interface
*/
class PrintHelloWorld implements Runnable{
// override Runnable run method
public void run(){
print();
}
private void print(){
for(int i=0; i<10; i++){
System.out.println(i + " - Hello, world");
}
}
}
To compile and run :
// to compile
javac ThreadExample.java
// to run
java ThreadExample
Multi-threading
Is the process of running multiple threads in the same process. For example a GUI application we can have an event thread that user input input event and IO thread that handle the io task
Concurrency
Is the act of processing multiple task at nearly the same time. It require context switching between tasks. This is what humans does by the way.
Parallelism
Is the act of processing multiple tasks on multiple CPUs at the same time.
Conclusion
Concurrency is dealing with a lot of things at once.
Parallelism is doing a lot of thing at once
Image that resume process, thread and operating system (OS) :
Process A : has 3 threads running
Process B : has 1 thread running
Process C : has 2 thread running
At each time on a cpu the operating manage to only run process and one thread inside that process.