Java Programming Tutorials

Java programming tutorials with many code examples!

Java synchronize static

Problem:

How to synchronize concurrent modifications of static data in Java? In this post we’re going to solution to this common, multi-threaded, problem. Read on!

In previous posts (Java synchronized method and Java synchronized object) we’ve shown how to safely modify object’s state in multi-threaded environment. Here the problem is a bit different, because data is static (class field instead of an instance field) as in the following example.

In the following code, the number is static and we have a static method that is used to modify it by a few threads concurrently:

package com.farenda.java.lang;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadSynchronizeOnClass {

    private static int number;

    public static boolean dec() {
        if (number > 0) {
            Thread.yield();
            --number;
            return true;
        }
        return false;
    }

    private static class Worker implements Runnable {

        private static int nth = 0;

        private final int id = ++nth;

        @Override
        public void run() {
            System.out.println("Starting worker: " + id);
            while (dec()) {
                System.out.printf("Decreased to %2d by worker: %2d%n",
                        ThreadSynchronizeOnClass.number, id);
            }
        }
    }

    public static void main(String[] args) {
        ThreadSynchronizeOnClass.number = 10;
        ExecutorService executor = Executors.newCachedThreadPool();
        for (int i = 1; i <= 10; ++i) {
            executor.execute(new Worker());
        }
        executor.shutdown();

        try {
            executor.awaitTermination(2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            //ignore
        }

        System.out.println("Number actually is: " + ThreadSynchronizeOnClass.number);
    }
}

When we run the above code, we can quickly notice that the result is not what we expected (sorted for readability):

Starting worker: 1
Starting worker: 2
Starting worker: 3
Starting worker: 4
Starting worker: 5
Starting worker: 6
Starting worker: 7
Starting worker: 8
Starting worker: 9
Starting worker: 10
Decreased to  9 by worker:  1
Decreased to  8 by worker:  1
Decreased to  7 by worker:  1
Decreased to  6 by worker: 10
Decreased to  5 by worker:  7
Decreased to  4 by worker:  6
Decreased to  3 by worker:  8
Decreased to  2 by worker:  9
Decreased to  1 by worker:  6
Decreased to  0 by worker:  9
Decreased to -1 by worker:  8
Decreased to -2 by worker:  7
Decreased to -3 by worker:  6
Number actually is: -3

Solution:

The problem can be solve is a similar way to the solutions that we’ve shown in posts Java synchronized method and Java synchronized object, namely:

  • synchronize access on static method level,
  • synchronize access using lock object.

Adding synchronized to the static method works, but has a bit different meaning as in the previous post:

public static synchronized boolean dec() {
    if (number > 0) {
        Thread.yield();
        --number;
        return true;
    }
    return false;
}

In case of static methods, the synchronized keyword operates on class lock instead of object’s lock. Remember that every class has corresponding instance of java.lang.Class object, which defines this class. So does our ThreadSynchronizeOnClass class. Now Threads that want to access dec method will try to lock on class of ThreadSynchronizeOnClass.

Synchronization using lock object works in the same way as described in Java synchronized object, but the lock object is a static field:

private static final Object lock = new Object();

public static boolean dec() {
    synchronized(lock) {
        if (number > 0) {
            Thread.yield();
            --number;
            return true;
        }
        return false;
    }
}

Running the above example with any of those synchronizations gives correct result:

Starting worker: 1
Starting worker: 2
Starting worker: 3
Starting worker: 4
Starting worker: 5
Starting worker: 6
Starting worker: 7
Starting worker: 8
Starting worker: 9
Starting worker: 10
Decreased to  9 by worker:  2
Decreased to  8 by worker:  2
Decreased to  7 by worker:  3
Decreased to  6 by worker:  3
Decreased to  5 by worker:  3
Decreased to  4 by worker:  1
Decreased to  3 by worker:  3
Decreased to  2 by worker:  2
Decreased to  1 by worker: 10
Decreased to  0 by worker: 10
Number actually is: 0

Presto! :-)

Share with the World!