SYNCHRONIZATION

                                                java synchronization

Synchronization for controlled access

The Java language provides two keywords for ensuring that data can be shared between threads in a controlled manner: synchronized and volatile. Synchronized has two important meanings: it ensures that only one thread executes a protected section of code at one time (mutual exclusion or mutex), and it ensures that data changed by one thread is visible to other threads (visibility of changes).

Without synchronization, it is easy for data to be left in an inconsistent state. For example, if one thread is updating two related values (say, the position and velocity of a particle), and another thread is reading those two values, it is possible that the second thread could be scheduled to run after the first thread has written one value but not the other, thus seeing one old and one new value. Synchronization allows us to define blocks of code that must run atomically, in which they appear to execute in an all-or-nothing manner, as far as other threads can tell.

The atomic execution or mutual exclusion aspect of synchronization is similar to the concept of critical sections in other operating environments.

Ensuring visibility of changes to shared data

Synchronization allows us to ensure that threads see consistent views of memory. Processors can use caches to speed up access to memory (or compilers may store values in registers for faster access). On some multiprocessor architectures, if a memory location is modified in the cache on one processor, it is not necessarily visible to other processors until the writer's cache is flushed and the reader's cache is invalidated. This means that on such systems, it is possible for two threads executing on two different processors to see two different values for the same variable! This sounds scary, but it is normal. It just means that you have to follow some rules when accessing data used or modified by other threads.

Volatile is simpler than synchronization and is suitable only for controlling access to single instances of primitive variables -- integers, booleans, and so on. When a variable is declared volatile, any write to that variable will go directly to main memory, bypassing the cache, while any read of that variable will come directly from main memory, bypassing the cache. This means that all threads see the same value for a volatile variable at all times. Without proper synchronization, it is possible for threads to see stale values of variables or experience other forms of data corruption.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class SyncExample
    {
        private static lockObject = new Object();
        private static class Thread1 extends Thread {
        public void run()
            {
                synchronized (lockObject)
                    {
                        x = y = 0;
                        System.out.println(x);
                    }
            }
    }
private static class Thread2 extends Thread
    {
        public void run()
            {
             
                synchronized (lockObject){
                x = y = 1;
                System.out.println(y);
            }
    }
    }
public static void main(String[] args)
    {
        new Thread1().run();
        new Thread2().run();
    }
}