Real-life Scenario
Suppose a person is withdrawing some amount of money from the bank and at the same time the ATM card registered with the same account number is carrying on withdrawal operation by some other user. Now suppose if withdrawing some amount of money from net banking makes funds in account lesser than the amount which needed to be withdrawal or the other way. This makes the bank unsafe as more funds are debited from the account than was actually present in the account making the bank very unsafe and is not seen in daily life. So what banks do is that they only let one transaction at a time. Once it is over then another is permitted.
Illustration:
Interpreting the same technology as there are two different processes going on which object in case of parallel execution is over headed by threads. Now possessing such traits over threads such that they should look after for before execution or in simpler words making them synchronized. This mechanism is referred to as Thread Safe with the use of the keyword ‘synchronized‘ before the common shared method/function to be performed parallel.
Technical Description:
As we know Java has a feature, Multithreading, which is a process of running multiple threads simultaneously. When multiple threads are working on the same data, and the value of our data is changing, that scenario is not thread-safe, and we will get inconsistent results. When a thread is already working on an object and preventing another thread from working on the same object, this process is called Thread-Safety. Now there are several ways to achieve thread-safety in our program namely as follows:
- Using Synchronization
- Using Volatile Keyword
- Using Atomic Variable
- Using Final Keyword
Conclusion: Hence, if we are accessing one thread at a time then we can say thread-safe program and if multiple threads are getting accessed then the program is said to be thread-unsafe that is one resource at a time can not be shared by multiple threads at a time.
Implementation:
- Java Program to illustrate Incomplete Thread Iterations returning counter value to Zero irrespective of iteration bound
- Java Program to Illustrate Complete Thread Iterations illustrating join() Method
- Java Program to Illustrate thread-unsafe or non-synchronizing programs as of incomplete iterations
- Java Program to Illustrate Thread Safe And synchronized Programs as of Complete iterations using ‘synchronized‘ Keyword.
Examples
// Example 1
// Java Program to illustrate Incomplete Thread Iterations
// Returning Counter Value to Zero
// irrespective of iteration bound
// Importing input output classes
import java.io.*;
// Class 1
// Helper Class
class TickTock {
// Member variable of this class
int count;
// Method of this Class
// It increments counter value whenever called
public void increment()
{
// Increment count by unity
// i.e count = count + 1;
count++;
}
//
}
// Class 2
// Synchronization demo class
// Main Class
class GFG {
// Main driver method
public static void main(String[] args) throws Exception
{
// Creating an object of class TickTock in main()
TickTock tt = new TickTock();
// Now, creating an thread object
// using Runnable interface
Thread t1 = new Thread(new Runnable() {
// Method
// To begin the execution of thread
public void run()
{
// Expression
for (int i = 0; i < 10000; i++) {
// Calling object of above class
// in main() method
tt.increment();
}
}
});
// Making above thread created to start
// via start() method which automatically
// calls run() method in Ticktock class
t1.start();
// Print and display the count
System.out.println("Count : " + tt.count);
}
}
// Example 2
// Java Program to Illustrate Complete Thread Iterations
// illustrating join() Method
// Importing input output classes
import java.io.*;
// Class 1
// Helper Class
class TickTock {
// Member variable of this class
int count;
// Method of this Class
public void increment()
{
// Increment count by unity
// whenever this function is called
count++;
}
}
// Class 2
// Synchronization demo class
// Main Class
class GFG {
// Main driver method
public static void main(String[] args) throws Exception
{
// Creating an object of class TickTock in main()
TickTock tt = new TickTock();
// Now, creating an thread object
// using Runnable interface
Thread t1 = new Thread(new Runnable() {
// Method
// To begin the execution of thread
public void run()
{
// Expression
for (int i = 0; i < 1000; i++) {
// Calling object of above class
// in main() method
tt.increment();
}
}
});
// Making above thread created to start
// via start() method which automatically
// calls run() method
t1.start();
// Now we are making main() thread to wait so
// that thread t1 completes it job
// using join() method
t1.join();
// Print and display the count value
System.out.println("Count : " + tt.count);
}
}
// Example 3
// Java Program to Illustrate Thread Unsafe Or
// Non-synchronizing Programs as of Incomplete Iterations
// Without using 'synchronized' program
// Importing input output classes
import java.io.*;
// Class 1
// Helper Class
class TickTock {
// Member variable of this class
int count;
// Method of this Class
public void increment()
{
// Increment count by unity
count++;
}
}
// Class 2
// Synchronization demo class
// Main Class
class GFG {
// Main driver method
public static void main(String[] args) throws Exception
{
// Creating an object of class TickTock in main()
TickTock tt = new TickTock();
// Now, creating an thread object
// using Runnable interface
Thread t1 = new Thread(new Runnable() {
// Method
// To begin the execution of thread
public void run()
{
// Expression
for (int i = 0; i < 100000; i++) {
// Calling object of above class
// in main() method
tt.increment();
}
}
});
// Now creating another thread and lets check
// how they increment count value running parallelly
// Thread 2
Thread t2 = new Thread(new Runnable() {
// Method
// To begin the execution of thread
public void run()
{
// Expression
for (int i = 0; i < 100000; i++) {
// Calling object of above class
// in main() method
tt.increment();
}
}
});
// Making above thread created to start
// via start() method which automatically
// calls run() method
t1.start();
t2.start();
// Now we are making main() thread to wait so
// that thread t1 completes it job
t1.join();
t2.join();
// Print and display the count
System.out.println("Count : " + tt.count);
}
}
// Example 4
// Java Program to Illustrate Thread Safe And
// Synchronized Programs as of Complete Iterations
// using 'synchronized' Keyword
// Importing input output classes
import java.io.*;
// Class 1
// helper Class
class TickTock {
// Member variable of this class
int count;
// Method of this Class
public synchronized void increment()
{
// Increment count by unity
count++;
}
//
}
// Class 2
// Synchronization demo class
// Main Class
class GFG {
// Main driver method
public static void main(String[] args) throws Exception
{
// Creating an object of class TickTock in main()
TickTock tt = new TickTock();
// Now, creating an thread object
// using Runnable interface
Thread t1 = new Thread(new Runnable() {
// Method
// To begin the execution of thread
public void run()
{
// Expression
for (int i = 0; i < 100000; i++) {
// Calling object of above class
// in main() method
tt.increment();
}
}
});
// Thread 2
Thread t2 = new Thread(new Runnable() {
// Method
// To begin the execution of thread
public void run()
{
// Expression
for (int i = 0; i < 100000; i++) {
// Calling object of above class
// in main() method
tt.increment();
}
}
});
// Making above thread created to start
// via start() method which automatically
// calls run() method
t1.start();
t2.start();
// Now we are making main() thread to wait so
// that thread t1 completes it job
t1.join();
t2.join();
// Print and display the count
System.out.println("Count : " + tt.count);
}
}
Output:
Case 1
Count : 0
Case 2
Count : 10000
Case 3
Count : 151138
Case 4
Count : 200000
Output Explanation:
In case 1 we can see that count is zero as initialized. Now we have two threads main thread and the thread t1. So there are two threads so now what happens sometimes instance is shared among both of the threads.
In case 1 both are accessing the count variable where we are directly trying to access thread via thread t1.count which will throw out 0 always as we need to call it with the help of object to perform the execution.
Now we have understood the working of synchronization is a thread that is nothing but referred to as a term Concurrency in java which in layman language is executing multiple tasks. Let us depict concurrency in threads with the help of a pictorial illustration.
Consider the task of multiplying an array of elements by a multiplier of 2. Now if we start multiplying every element randomly wise it will take a serious amount of time as every time the element will be searched over and computer. By far we have studied multithreading above in which we have concluded to a single line that thread is the backbone of multithreading.
So incorporating threads in the above situation as the machine is quad-core we here take 4 threads for every core where we divide the above computing sample set to (1/4)th resulting out in 4x faster computing. If in the above scenario it had taken 4 seconds then now it will take 1 second only. This mechanism of parallel running threads in order to achieve faster and lag-free computations is known as concurrency.
Note: Go for multithreading always for concurrent execution and if not using this concept go for sequential execution despite having bigger chunks of code as safety to our code is the primary issue.
Java Multithreading Tutorial
Threads are the backbone of multithreading. We are living in a real world which in itself is caught on the web surrounded by lots of applications. With the advancement in technologies, we cannot achieve the speed required to run them simultaneously unless we introduce the concept of multi-tasking efficiently. It is achieved by the concept of thread.
Contact Us