Synchronization in Java

In Java, synchronization is a mechanism that ensures that only one thread can access a shared resource at a time. Synchronization prevents race conditions and other concurrency-related issues that can occur when multiple threads access the same resource simultaneously. Synchronization is implemented using the synchronized keyword in Java.

There are two-way to achieve synchronization as given below:

* Synchronized method
* Synchronized block

When a method or a block of code is declared as synchronized, only one thread can execute that code at a time. Other threads that try to access the same code block will be blocked until the executing thread releases the lock.

Here's an example that demonstrates the use of synchronization in Java using Synchronized method:

                
    public class SynchronizedExample {
        private int count = 0;

        public synchronized void increment() {
            count++;
        }

        public synchronized int getCount() {
            return count;
        }
    }
                
            

In this example, we have a SynchronizedExample class that has two methods, increment() and getCount(), that access a shared variable count. Both methods are declared as synchronized, which means that only one thread can execute these methods at a time.

To use this class in a multithreaded environment, you can create multiple threads that access the increment() method to increment the value of count, and another thread that accesses the getCount() method to get the value of count. Here's an example:

                
    public class SynchronizedThreadExample {
        public static void main(String[] args) throws InterruptedException {
            SynchronizedExample example = new SynchronizedExample();
            Runnable runnable = () -> {
                for (int i = 0; i < 100000; i++) {
                    example.increment();
                }
            };
            Thread thread1 = new Thread(runnable);
            Thread thread2 = new Thread(runnable);
            thread1.start();
            thread2.start();
            thread1.join();
            thread2.join();
            System.out.println("Count: " + example.getCount());
        }
    }
                
            

In this example, we have a SynchronizedThreadExample class that creates two threads that access the increment() method of SynchronizedExample. Each thread increments the value of count 100,000 times. After both threads have finished their execution, the main thread accesses the getCount() method to get the final value of count.

It's important to note that synchronization can cause performance issues in multithreaded environments as threads may need to wait for a lock to be released. Therefore, synchronization should be used only when necessary and with caution. Additionally, you should avoid using synchronized on large methods or blocks of code, as it can cause long waits and potential deadlock situations.