Saturday, July 12, 2014

Concurrency : Using the "synchronized" keyword [Java]

Let us suppose you have two fields in a class and a method that modifies the fields non-atomically.
Let's say you need to increment int fields by two and you use

1  field1++;
2  Thread.yield(); //This is optional. It just says "I've done the important work, some other thread may be                                  //selected for execution now
3  field1++;

so that the current thread gets it's operations paused in the middle while other thread is selected by the JVM
for execution. According to our assumptions, the value of field1 should always be even, otherwise exception
is to be thrown.

Here is the code without synchronization keyword [this fails: ]

import java.util.concurrent.*;

 class TwoDataFields implements Runnable{

    private static int data1 = 0;
    private static int data2 = 0;

    public static  void manipulateData() {
        data1++;
        Thread.yield();
        data1++;
        data2--;
        Thread.yield();
        data2--;
    }

    public void run() {
        for (int i = 0; i < 1000; ++i) {
            manipulateData();
            readFields();
        }
    }

    public static  void readFields() {
        System.out.println("Data1 = " + data1);
        System.out.println("Data2 = " + data2 + "\n");

        if (data1 % 2 != 0) {
            System.err.println("Data1 is not even!");
            throw new RuntimeException();
        }
        if (data2 % 2 != 0) {
            System.err.println("Data2 is not even!");
            throw new RuntimeException();
        }
    }
}

public class TesterClass{

    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();

        for (int i = 0; i < 10000; ++i) {
            exec.submit(new TwoDataFields());
        }

        exec.shutdown();
    }
}


Adding the synchronized keyword solves the problem:
Only one thread is able to access manipulateData() and readFields() at a time so that the data fields
are not left in improper states.

import java.util.concurrent.*;

 class TwoDataFields implements Runnable{

    private static int data1 = 0;
    private static int data2 = 0;

    public static synchronized void manipulateData() {
        data1++;
        Thread.yield();
        data1++;
        data2--;
        Thread.yield();
        data2--;
    }

    public void run() {
        for (int i = 0; i < 1000; ++i) {
            manipulateData();
            readFields();
        }
    }

    public static  synchronized void readFields() {
        System.out.println("Data1 = " + data1);
        System.out.println("Data2 = " + data2 + "\n");

        if (data1 % 2 != 0) {
            System.err.println("Data1 not even!");
            throw new RuntimeException();
        }
        if (data2 % 2 != 0) {
            System.err.println("Data2 not even!");
            throw new RuntimeException();
        }
    }
}

public class TesterClass{

    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();

        for (int i = 0; i < 1000; ++i) {
            exec.submit(new TwoDataFields());
        }

        exec.shutdown();
    }
}

Now this doesn't throw the Exceptions.



No comments:

Post a Comment