When more than one thread has to use a shared resource, Java finds way of ensuring that only one thread uses the resources at one point of time; this is called synchronization.
In Java, thread synchronization refers to the mechanisms used to ensure that multiple threads access shared resources in a safe and predictable manner. It is important to synchronize threads when multiple threads access the same shared resources, such as variables or objects, to avoid race conditions, where the outcome of the program depends on the relative timing of events between the threads.
Thread safety is the property of a program that guarantees that it behaves correctly when executed concurrently by multiple threads. A thread-safe program is one that guarantees thread safety by using synchronization to ensure that shared resources are accessed in a predictable and safe manner.
In java, each object is associated with a lock. The term lock refers to the access granted to a particular thread that has entered a synchronized method.
Monitor refers to a portion of the code in the program. It contain one specific region that can be occupied by only one thread at a time. This specific region within a monitor is known as critical section.
A thread has exclusive lock from the time it enters the critical section to the time it leaves. That is, the data (or resources) is exclusively served for the thread, and any other thread has to wait to access that data.
The key concept in synchronization is the monitor.
When there are several synchronized methods attempting to act on an object, only one synchronized method may be active on an object at one instance of time and all other threads attempting to invoke synchronized methods must be wait.
There are two main mechanisms for thread synchronization in Java: synchronized methods and synchronized blocks. Synchronized methods ensure that only one thread can execute the method at a time, while synchronized blocks allow more fine-grained control over which parts of the code are synchronized.
To make a method thread-safe in Java, you can add the synchronized
keyword to the method declaration. This ensures that only one thread can execute the method at a time, preventing race conditions.
Here is an example of a thread-safe Java class using synchronized methods:
class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized void decrement() { count--; } public synchronized int getCount() { return count; } } class CounterThread extends Thread { private Counter counter; public CounterThread(Counter counter) { this.counter = counter; } public void run() { for (int i = 0; i < 10000; i++) { counter.increment(); } } } public class SynchronizationExample { public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CounterThread thread1 = new CounterThread(counter); CounterThread thread2 = new CounterThread(counter); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println("Count: " + counter.getCount()); } }
In this program, we have a Counter
class that has three synchronized methods: increment
, decrement
, and getCount
. These methods are synchronized to prevent race conditions and ensure that only one thread can access them at a time.
We also have a CounterThread
class that extends the Thread
class and has a reference to a Counter
object. The run
method of this class simply calls the increment
method of the Counter
object 10,000 times.
In the main
method of the SynchronizationExample
class, we create two CounterThread
objects and start them. We then wait for them to finish using the join
method. Finally, we print the value of the count using the getCount
method of the Counter
object.
When we run this program, we should see that the count is always 20,000, indicating that the synchronization is working correctly and preventing race conditions.
In Java, synchronized blocks are another way to achieve thread safety and prevent race conditions. A synchronized block is a block of code that is synchronized on a specific object.
Here is an example program that demonstrates the use of synchronized blocks in Java:
class Counter { private int count = 0; public void increment() { synchronized (this) { count++; } } public void decrement() { synchronized (this) { count--; } } public int getCount() { synchronized (this) { return count; } } } class CounterThread extends Thread { private Counter counter; public CounterThread(Counter counter) { this.counter = counter; } public void run() { for (int i = 0; i < 10000; i++) { counter.increment(); } } } public class SynchronizedBlockExample { public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); CounterThread thread1 = new CounterThread(counter); CounterThread thread2 = new CounterThread(counter); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println("Count: " + counter.getCount()); } }
In this program, we have a Counter
class that has three methods: increment
, decrement
, and getCount
. Each of these methods is synchronized on the this
object using a synchronized block. This ensures that only one thread can access the block of code inside the block at a time.
We also have a CounterThread
class that extends the Thread
class and has a reference to a Counter
object. The run
method of this class simply calls the increment
method of the Counter
object 10,000 times.
In the main
method of the SynchronizedBlockExample
class, we create two CounterThread
objects and start them. We then wait for them to finish using the join
method. Finally, we print the value of the count using the getCount
method of the Counter
object.
When we run this program, we should see that the count is always 20,000, indicating that the synchronization is working correctly and preventing race conditions.
In summary, thread synchronization and thread safety are important
concepts in Java that ensure that multiple threads can access shared
resources in a safe and predictable manner. Synchronized methods and
synchronized blocks are two mechanisms used to achieve thread
synchronization and thread safety in Java.
0 comments :
Post a Comment
Note: only a member of this blog may post a comment.