How to protect shared data when it is accessed by multiple threads?

To protect the variables from shared access, we use volatile and AtomicReference(s). If it is a method or a block of code, then we use Synchronized or explicit locking. Apart from these, ThreadLocal is another way to protect the shared data where we distribute the copy of the shared variable to each thread. This post provides more details about each approach with a working example.

Volatile 
Volatile variables makes the reads and writes to the main memory. But, it doesn't give synchronous behavior.  To get the synchronous behavior, it has to be mixed with synchronized while performing read and writes.

Atomic Variables

Atomic variables support compound operations like increment, decrement on variables in an atomic or synchronous manner. For only such concurrent operations supported by the java atomic API, we can use them as an alternative for synchronization since they are fast and non-blocking.

Synchronized 
  1. It protects methods/code blocks from concurrent access.
  2. Synchronized Method or Synchronized block ensures that the code inside it will be accessed by a single thread at any point of time.
A detailed example of Synchronized is available here>>.
    Lock Interface
    1. The functionality of Lock Interface and Synchronized is same except that Lock interface provides more control on lock acquisition when compared to Synchronized block. Below are the different variants of lock acquisition supported.
    2. Syntax-wise, In the synchronized approach, locking, unlocking happens implicitly whereas, in this approach, they have to be set explicitly.

    • Lock Fairness - Longest waiting thread gets the lock.
    • Lock Interruptibility - Ability to interrupt thread while waiting for the lock. Useful in the scenarios where a thread is waiting for the lock for a very long time 
    • Lock timeout - Ability to timeout while waiting for the lock without blocking for a long time
    • tryLock() - Try for lock without blocking


    Thread Local

    1. ThreadLocal provides thread safety to the share reference not by restricting multiple thread access on the reference, instead, it creates a copy of the shared reference for each thread. so, each thread uses its own copy which cannot be shared with the other thread. Since, each thread has its own copy mutiple access on the shared variable will not have any impact
    2. We can wrap any thread-unsafe object in ThreadLocal to protect that object from thread safety
    3. ThreadLocal variables in Java are generally private static mutable fields in Classes. They are used in scenarios where per-thread context instances like UserContext, TransactionContext etc., has to be created.
    In the below example, ThreadLocal is used to create DateFormat (eg. of UserContext information) instance. 2 threads are created and each thread accessed the date format twice in their threads. Since each thread created its own copy of date format instance, multiple access on date format did not create any impact.


    public class ThreadLocalExample {
    
        public static void main(String[] args) {
            for (int i = 0; i < 2; i++) {
                new Thread(() -> {
                    for (int j = 0; j< 2; j++) {
                        System.out.println(Thread.currentThread().getName() + " : " + DateFormatter.getDateFormatter().format(new Date()));
                    }
                }, "THREAD-"+i).start();
            }
        }
    }
    class DateFormatter {
        static boolean flip = false;
        private static final ThreadLocal<SimpleDateFormat> dateFormatHolder = new ThreadLocal<SimpleDateFormat>(){
            @Override
            protected SimpleDateFormat initialValue() {
                System.out.println("Creating SimpleDateFormat for Thread : "+ Thread.currentThread().getName());
                if(flip())
                    return  new SimpleDateFormat("dd/MM/yyyy");
                else
                    return  new SimpleDateFormat("dd-MM-yyyy");
            }
        };
    
        public static DateFormat getDateFormatter(){
            return dateFormatHolder.get();
        }
    
        private static boolean flip() {
            return flip =(flip==false)?true:false;
        }
    }
    
    Output
    Creating SimpleDateFormat for Thread : THREAD-0
    Creating SimpleDateFormat for Thread : THREAD-1
    THREAD-1 : 28-07-2018
    THREAD-0 : 28/07/2018
    THREAD-0 : 28/07/2018
    THREAD-1 : 28-07-2018
    

    Comments

    Popular posts from this blog

    Distributed database design using CAP theorem

    SQL Analytical Functions - Partition by (to split resultset into groups)

    Easy approach to work with files in Java - Java NIO(New input output)