Welcome folks ,
Here's an important topic in the field of programming - Synchronization of threads .
Thread - A thread is a single sequence stream within in a process. Threads have some properties of processes, therefore they are also called as lightweight processes .
Thread synchronization is very important because unsynchronized threads lead to race condition .
Lets see how to synchronize the execution of threads in JAVA.
Execute the below program and check the output
class WeTechies
{
public static void main(String args[])
{
WeTechies1 t1 = new WeTechies1("t1: ");
WeTechies1 t2 = new WeTechies1("t2: ");
t1.start();
t2.start();
boolean t1IsAlive = true;
boolean t2IsAlive = true;
do {
if (t1IsAlive && !t1.isAlive()) {
t1IsAlive = false;
System.out.println("t1 is not alive.");
}
if (t2IsAlive && !t2.isAlive()) {
t2IsAlive = false;
System.out.println("t2 is not alive.");
}
} while(thread1IsAlive || thread2IsAlive);
}
}
class WeTechies1 extends Thread
{
static String message[] = { "Welcome", "to", "we", "techies ."};
public WeTechies1(String th)
{
super(th);
}
public void run()
{
String threadname = getName();
for (int i=0;i<message.length;++i) {
letsWait();
System.out.println(threadname + message[i]);
}
}
void letsWait()
{
try {
sleep((long)(3000*Math.random()));
} catch (InterruptedException ex) {
System.out.println("Thread has been Interrupted!" + ex);
}
}
}
This is the output obtained from the above program
t1: Welcome
t1: to
t1: we
t2: Welcome
t2: to
t1: techies .
t1 is not alive.
t2: we
t2: techies .
t2 is not alive.
But the expected output is Welcome
to
we
techies
We get this un expected output due to the non synchronization between the threads t1 and t2.
In the above program we have created a multi threaded program by creating the WeTechies1 as a subclass of the Thread class , which is done using the keyword extend.
Now lets create a program with similar behavior, but we create our threads as objects of the class WeTechies1, which is not a subclass of Thread. WeTechies1 will implement the Runnable interface and objects of WeTechies1 will be executed as threads by passing them as arguments to the Threadconstructor.
class WeTechies
{
public static void main(String args[])
{
Thread t1 = new Thread(new WeTechies2("thread1: "));;
Thread t2 = new Thread(new WeTechies2("thread2: "));;
t1.start();
t2.start();
boolean t1IsAlive = true;
boolean t2IsAlive = true;
do {
if (t1IsAlive && !t1.isAlive()) {
t1IsAlive = false;
System.out.println("t1 is not alive.");
}
if (t2IsAlive && !t2.isAlive()) {
t2IsAlive = false;
System.out.println("t2 is not alive.");
}
} while(t1IsAlive || t2IsAlive);
}
}
class WeTechies2 implements Runnable
{
static String message[] = { "Welcome", "to", "we", "techies ."};
String threadname;
public WeTechies2(String id)
{
threadname = id;
}
public void run()
{
for (int i=0;i<message.length;++i) {
letsWait();
System.out.println(threadname + message[i]);
}
}
void letsWait()
{
try {
Thread.currentThread().sleep((long)(3000*Math.random()));
} catch (InterruptedException ex) {
System.out.println("Thread has been Interrupted!" + ex);
}
}
}
The output of the above program is
thread1: Welcome
thread2: Welcome
thread1: to
thread2: to
thread1: we
thread2: we
thread2: techies .
t2 is not alive.
thread1: techies .
t1 is not alive.
You will find the output to be similar to the previous program but the difference lies in the way the threads are created , this program does not extend the Thread class to create the thread like the previous program did , rather it implements the Runnable interface in order to create the thread.
Now lets synchronize the threads in order to get our expected output.
This can be done using the synchronized keyword.
Consider the below program where we synchronize the execution of the threads 1 and 2 using the keyword synchronized in the output() method
class WeTechiesSynchronization
{
public static void main(String args[])
{
WeTechies thread1 = new WeTechies("thread1: ");
WeTechies thread2 = new WeTechies("thread2: ");
thread1.start();
thread2.start();
boolean thread1IsAlive = true;
boolean thread2IsAlive = true;
do {
if (thread1IsAlive && !thread1.isAlive()) {
thread1IsAlive = false;
System.out.println("Thread 1 is dead.");
}
if (thread2IsAlive && !thread2.isAlive()) {
thread2IsAlive = false;
System.out.println("Thread 2 is dead.");
}
} while(thread1IsAlive || thread2IsAlive);
}
}
class WeTechies extends Thread
{
static String message[] = { "Welcome", "to", "we", "techies ."};
public WeTechies(String id)
{
super(id);
}
public void run()
{
WeTechiesSynchronizedOutput.output(getName(),message);
}
void randomWait()
{
try {
sleep((long)(3000*Math.random()));
} catch (InterruptedException x) {
System.out.println("Interrupted!");
}
}
}
class WeTechiesSynchronizedOutput
{
public static synchronized void output(String name,String list[])
{
for(int i=0;i<list.length;++i) {
WeTechies t = (WeTechies) Thread.currentThread();
t.randomWait();
System.out.println(name+list[i]);
}
}
}
The ouput of the above program is
thread1: Welcome
thread1: to
thread1: we
thread1: techies .
Thread 1 is dead.
thread2: Welcome
thread2: to
thread2: we
thread2: techies
Thread 2 is dead.
Now we have got the expected output by making use of the synchronized keyword.
This way the race conditions can be handled hence leading to synchronized execution of the threads.
Please feel free to leave your comments or doubts
thank you :)