1

Disclaimer: This code is copied from synchronized blocks for static and non-static methods

I made some modification to it. I want to know how to make threads call both synchronized static and non-static methods. I can make it work by wrapping the non-static method in a synchronized block. Is there any other way?

public class StaticNonStaticSynch { public static void main(String[] args) { final StaticNonStaticTest staticNonStaticTest = new StaticNonStaticTest(); Runnable runnable1 = new Runnable() { @Override public void run() { staticNonStaticTest.nonStaticMethod(); } }; Runnable runnable2 = new Runnable() { @Override public void run() { StaticNonStaticTest.staticMethod(); } }; Thread thread1 = new Thread(runnable1, "First Thread"); Thread thread2 = new Thread(runnable2, "Second Thread"); thread1.start(); thread2.start(); } } class StaticNonStaticTest { void nonStaticMethod() { //synchronized (StaticNonStaticTest.class){ for(int i=0;i<50;i++) { System.out.println("Non - Static method called by " + Thread.currentThread().getName() +" : = "+i); } // } } static synchronized void staticMethod() { for(int i=0;i<50;i++) { System.out.println("Static method called by " + Thread.currentThread().getName() +" : = "+i); } } } 

2 Answers 2

4

Remember that this:

public class MyClass { public synchronized void doSomething() { // Do something } public synchronized static void doSomethingStatic() { // Do something static } } 

Essentially compiles to this:

public class MyClass { public void doSomething() { synchronized(this) { // Do something } } public static void doSomethingStatic() { synchronized(MyClass.class) { // Do something static } } } 

Notice that they don't synchronize on the same thing. To fix this, create an object for both of them to lock on (known as a mutually exclusive object, or a "mutex"):

public class MyClass { private static final Object MUTEX = new Object(); public void doSomething() { synchronized(MUTEX) { // Do something } } public static void doSomethingStatic() { synchronized(MUTEX) { // Do something static } } } 

That should make it so that only one of these two methods are running at the same time across multiple threads.

A couple tips:

  • Always use synchronized(variable) on a variable that's final.
  • The MUTEX doesn't have to be strictly a mutex, it could be an actual object. See the example below.
  • Remember how the synchronized modifier on methods is effectively implemented. It's just like a synchronized block on this or MyClass.class.

Besides having an object that's strictly a mutex, you can use any field that's final. For example, to synchronize on a Map during iteration:

public class MyClass { private static final Map<String, String> map = new HashMap<String, String>(); // Java 6 private static final Map<String, String> map = new HashMap<>(); // Java 7 public static void put(String k, String v) { synchronized(map) { map.put(k, v); } } public static void printAll() { synchronized(map) { for (Entry<String, String> entry : map.entrySet()) { System.out.println(entry.getKey() + ":" + entry.getValue()); } } } } 

This code guarantees that you'll never get a ConcurrentModificationException

Sign up to request clarification or add additional context in comments.

2 Comments

@brian : What if we get a lock on an instance of MyClass? Will it still guarantee that we won't get a ConcurrentModificationException since no other thread will be able to access synchronized block in put() when the current thread is in printAll() and also the map is private?
@Kode Yes, it will guarantee non-concurrent access, but anything else that synchronizes on the class will also cause that section of code to be blocked. It's better to scope your synchronization down as much as possible to prevent bottlenecks.
2

You can have both methods internally synchronize on a common lock object. Otherwise, the only way to have the instance method block while the static method executes is to synchronize on the class object (as you have in the commented lines).

Synchronized instance methods synchronize on the object instance; synchronized static methods synchronize on the class instance. Note that synchronized static methods might execute simultaneously if there are two instances of the class (say, from different class loaders). You usually would know if this is happening, because you have to do considerable work to make it happen.

Here's one way to synchronize both static and instance methods on a common lock object:

class StaticNonStaticTest { private static final Object LOCK_OBJECT = new Object(); void nonStaticMethod() { synchronized (LOCK_OBJECT) { for (int i=0; i<50; i++) { System.out.println("Non - Static method called by " + Thread.currentThread().getName() + " : = " + i); } } } static void staticMethod() { synchronized (LOCK_OBJECT) { for (int i=0; i<50; i++) { System.out.println("Static method called by " + Thread.currentThread().getName() +" : = "+i); } } } } 

1 Comment

How can I "have both methods internally synchronize on a common lock object"?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.