128

I know that using the synchronize keyword before a method brings synchronization to that object. That is, 2 threads running the same instance of the object will be synchronized.

However, since the synchronization is at the object level, 2 threads running different instances of the object will not be synchronized. If we have a static variable in a Java class that is called by the method, we would like it to be synchronized across instances of the class. The two instances are running in 2 different threads.

Can we achieve synchronization in the following way?

public class Test  
{  
   private static int count = 0;  
   private static final Object lock= new Object();    
   public synchronized void foo() 
  {  
      synchronized(lock)
     {  
         count++;  
     }  
  }  
}

Is it true that since we have defined an object lock that is static and we are using the keyword synchronized for that lock, the static variable count is now synchronized across instances of class Test?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Anonymous
  • 4,133
  • 10
  • 31
  • 38

5 Answers5

208

There are several ways to synchronize access to a static variable.

  1. Use a synchronized static method. This synchronizes on the class object.

    public class Test {
        private static int count = 0;
    
        public static synchronized void incrementCount() {
            count++;
        }
    } 
    
  2. Explicitly synchronize on the class object.

    public class Test {
        private static int count = 0;
    
        public void incrementCount() {
            synchronized (Test.class) {
                count++;
            }
        }
    } 
    
  3. Synchronize on some other static object.

    public class Test {
        private static int count = 0;
        private static final Object countLock = new Object();
    
        public void incrementCount() {
            synchronized (countLock) {
                count++;
            }
        }
    } 
    

Method 3 is the best in many cases because the lock object is not exposed outside of your class.

Flexo
  • 87,323
  • 22
  • 191
  • 272
Darron
  • 21,309
  • 5
  • 49
  • 53
  • 1
    1. the first one even don't need a lock object, shouldn't it be the best? – Baiyan Huang Jul 10 '12 at 02:24
  • 4
    2. declare count as volatile would also works, as volatile makes sure the variable is synchronized. – Baiyan Huang Jul 10 '12 at 02:25
  • 9
    The reason #3 is the best is that any random bit of code could synchronize on `Test.class` and potentially spoil your day. Also, class initialization runs with a lock on the class held, so if you've got crazy class initializers you can give yourself headaches. `volatile` doesn't help for `count++` because it's a read / modify / write sequence. As noted in a different answer, `java.util.concurrent.atomic.AtomicInteger` is likely the right choice here. – fadden Apr 17 '13 at 23:35
  • 4
    Don't forget to synchronize the read operation on count if you want to read the correct value as set by other threads. Declaring it volatile (in addition to synchronized write) will also help with this. – n0rm1e Apr 24 '13 at 14:27
  • 1
    @Ferrybig no, you are locking on `Test.class` . `this` would be the lock for synchronized **non-static** methods – user3237736 Apr 12 '18 at 00:35
63

If you're simply sharing a counter, consider using an AtomicInteger or another suitable class from the java.util.concurrent.atomic package:

public class Test {

    private final static AtomicInteger count = new AtomicInteger(0); 

    public void foo() {  
        count.incrementAndGet();
    }  
}
Kevin
  • 30,111
  • 9
  • 76
  • 83
4

Yes it is true.

If you create two instance of your class

Test t1 = new Test();
Test t2 = new Test();

Then t1.foo and t2.foo both synchronize on the same static object and hence block each other.

richs
  • 4,699
  • 10
  • 43
  • 56
1

We can also use ReentrantLock to achieve the synchronization for static variables.

public class Test {

    private static int count = 0;
    private static final ReentrantLock reentrantLock = new ReentrantLock(); 
    public void foo() {  
        reentrantLock.lock();
        count = count + 1;
        reentrantLock.unlock();
    }  
}
Sunil
  • 19
  • 1
  • 8
0

You can synchronize your code over the class. That would be simplest.

   public class Test  
    {  
       private static int count = 0;  
       private static final Object lock= new Object();    
       public synchronized void foo() 
      {  
          synchronized(Test.class)
         {  
             count++;  
         }  
      }  
    }

Hope you find this answer useful.

Jafar Ali
  • 1,084
  • 3
  • 16
  • 39
  • 2
    This will work, but as mentioned elsewhere by @Fadden, beware that any other thread could also synchronize on `Test.class` and affect behaviour. This is why synchronizing on `lock` might be preferred. – sbk Sep 03 '13 at 04:32
  • What you are saying is correct. That is why I clearly mention that the above is the simplest approach. – Jafar Ali Dec 13 '16 at 15:05