Java thread safe for you

Q

How should we guarantee thread safety in Java?

Conclusion

Storm

Java language specification

Especially in Java, the following control syntax is related to the elements that have appeared so far.

Practice

Consider the case where foo () and bar () are called from different threads multiple times at irregular intervals for the following implementation.

   public void foo() {
       _object.update();  // _Processing that changes the internal state of object
   }
   
   public void bar() {
       if (_object.enabled()) {
           _object.getData();  // enabled()Exception occurs when called when is false
       }
   }

No synchronized block

Since there is no guarantee of atomicity in the processing of bar (), the methods may be called in the following order. _object.enabled() -> _object.update() -> _object.getData()

   public void foo() {
       _object.update();
   }
   
   public void bar() {
       if (_object.enabled()) {
           _object.getData();  // _The internal state of object is not guaranteed
       }
   }

There is a synchronized block

A guarantee of synchronization is added during the processing within the block, that is, the atomicity is also guaranteed. 【 _object.update() 】 -> 【 _object.enabled() -> _object.getData() 】 -> 【 _object.update() 】

It is easy to understand if you have an image that is stored in the processing queue in block units.

   public void foo() {
       synchronized (this) {
           _object.update();
       }
   }
   
   public void bar() {
       synchronized (this) {
           if (_object.enabled()) {
               _object.getData();  // _The internal state of object is guaranteed
           }
       }
   }

There is only a part of synchronized block

Synchronize operations between blocks that specify the same object as an argument

The synchronized block is just a guarantee of synchronization as described above. The following implementation does not guarantee synchronization for the processing inside bar ().

   public void foo() {
       _object.update();
   }
   
   public void bar() {
       synchronized (this) {
           if (_object.enabled()) {
               _object.getData();  // _The internal state of object is not guaranteed
           }
       }
   }

Synchronized block for another object

A supplement just in case. Synchronization is not guaranteed for operations between blocks that specify different objects as arguments.

   public void foo() {
       synchronized (_SOME_OBJECT) {
           _object.update();
       }
   }
   
   public void bar() {
       synchronized (this) {
           if (_object.enabled()) {
               _object.getData();  // _The internal state of object is not guaranteed
           }
       }
   }

Digression

About lock objects

Deadlock resistance

In order to minimize the occurrence of deadlock, it is desirable to apply the following principles to the implementation.

Lock object selection

Also, in either case the lock object must not be null. This is guaranteed by adding the final modifier.

  //Recommended implementation

  class Shared {
      private final Object _LOCK_OBJECT = new Object();  //Don't make it static

      public void foo() {
          synchronized (_LOCK_OBJECT) {
              // do something
          }
      }

      public void bar() {
          synchronized (_LOCK_OBJECT) {
              // do something
          }
      }
  }

  class User {
      public void sample() {
          final Shared object = new Shared();
          new Thread(() -> object.foo()).start();
          new Thread(() -> object.bar()).start();
      }
  }
  //Implementations that use this for lock objects
  
  class Shared {
      public void foo() {
          synchronized (this) {
              // do something
          }
      }
      public void bar() {
          synchronized (this) {
              // do something
          }
      }
  }

  class User {
      public void sample() {
          final Shared object = new Shared();
          //This object instance serves as a reference to the shared internal implementation's lock object.
          //Therefore, it violates the principle of "minimizing the shared range of lock objects".
      }
  }

Lock object definition

Similarly, according to the principle of minimizing the sharing range, a lock object should be defined for each target for which thread safety is to be guaranteed.

  class Shared {
      //Lock target
      private final Data _dataA = new Data();
      private final Data _dataB = new Data();
      private final Data _dateC = new Data();
      private final Validator = _validator = new Validator();

      //Lock object
      private final Object _DATA_A_LOCK = new Object();
      private final Object _DATA_B_LOCK = new Object();
      private final Object _DATA_C_LOCK = new Object();

      public void foo() {
          synchronized (_DATA_A_LOCK) {
              _dataA.update();
          }
          synchronized (_DATA_B_LOCK) {
              _dataB.update();
          }
          synchronized (_DATA_C_LOCK) {
              _validator.execute();
              _dataC.update();
          }
      }

      public void bar() {
          synchronized (_DATA_A_LOCK) {
              _dataA.get();
          }
          synchronized (_DATA_B_LOCK) {
              _dataB.get();
          }
          synchronized (_DATA_C_LOCK) {
              _validator.execute();
              _dataC.get();
          }
      }
  }

one thing

Recommended Posts

Java thread safe for you
Java local variables are thread safe
Java for statement
[Java] Package for management
Java Programming Thread Runnable
Java for beginners, data hiding
[Java] Tips for writing source
Java installation location for mac
Java thread to understand loosely
Java application for beginners: stream
Java while and for statements
Weak reference of JAVA reused instance allocated for each thread
[Java] New Thread generation method (1)
[Java & SpringBoot] Environment Construction for Mac
Notes on Android (java) thread processing
Settings for SSL debugging in Java
Generics of Kotlin for Java developers
Diary for Java SE 8 Silver qualification
[For Java beginners] About exception handling
Classes and instances Java for beginners
Modern best practices for Java testing
Do you use Stream in Java?
[Java] Where did you try using java?