The characteristics of the Synchronized

  1. Memory visibility: When a thread releases a lock, the JMM (Java Memory Model) flusher the shared variables in the thread’s local Memory to the main Memory. When A thread acquises A lock, the JMM invalidates the thread’s local memory so that the critical section code protected by the monitor must read the shared variable from main memory (essentially, thread A sends A message to thread B through main memory)

  2. Atomicity of operations: The JMM provides guaranteed atomicity for accessing basic data types (there are two main steps in writing a working memory variable to main memory: Store and write), but actual business processing scenarios often require a wider range of atomicity guarantees, so the model also provides synchronized blocks to ensure atomicity

  3. Order: This concept is relative, if in this thread, all operations are ordered, if another thread is in a thread to observe, all operations are chaotic, the former is characterized by serial behavior within the thread, the other is “instruction reordering” and “working memory and main memory synchronization delay” phenomenon, The JMM provides volatile and synchronized to ensure order between threads

Underlying principle of Synchronized

The JVM implements method synchronization and code block synchronization based on entering and exiting Monitor (Monitor lock) objects

  • synchronizedThe modified method adds one to the bytecodeACC_SYNCHRONIZEDflagWhen a thread executes a method, the JVM checks that methodACC_SYNCHRONIZEDWhether the access flag is set, and if so the thread will fetch the corresponding objectmonitorObject (There is one and only one corresponding to each objectmonitorObject), the method body is executed after the method is successfully obtained, and the method is released after executionmonitorObject that is not available to any other thread during this periodmonitorobject
  • The synchronized code block is inserted before the synchronized code blockmonitorenter, inserted after the end of the synchronized code blockmonitorexit. According to the requirements of the VM specificationsmonitorenterCommand, first attempt to acquire the lock of the object (monitor), if the object is not locked, or the current thread already owns the lock on that object, increment the counter of the lock by 1; Accordingly, in executionmonitorexitThe command will decrease the lock counter by one, and when the counter is reduced to zero, the lock is released. If the object lock fails to be acquired, the current thread blocks and waits until the object lock is released by another thread

Note:

  1. synchronizedSynchronized blocks are reentrant to the same thread and do not lock themselves
  2. The synchronization block blocks subsequent threads until the incoming thread finishes executing

Mutex Lock

A Monitor Lock is essentially implemented by relying on the underlying operating system’s Mutex Lock. Each object corresponds to a “mutex” tag, which ensures that only one thread can access the object at any one time

Mutex: Used to protect critical sections and ensure that only one thread accesses data at a time. To access a shared resource, the mutex is locked. If the mutex is locked, the calling thread blocks until the mutex is unlocked. After access to the shared resource is complete, the mutex is unlocked

How Mutex works:

  1. To apply for a Mutex
  2. If successful, the Mutex is held
  3. If it fails, proceedspinThe spin.spinThe process is to wait onlineMutexAnd repeatedly initiates a Mutex gets until a Mutex is obtained or reachedspin_countlimit
  4. Depending on the working modeyiledorsleep
  5. If reachsleepLimitations are either actively aroused or completedyield, then repeat steps 1~4 until obtained

Since Java threads are mapped to the native threads of the operating system, blocking or waking up a thread requires the operating system to help complete the transition from user state to core state, so the state transition takes a lot of processor time. Synchronized is therefore a heavyweight operation in the Java language

JDK 1.6 improvements: Synchronized compared to ReentrantLock in the java.util.concurrent package, due to the locking optimizations added in JDK1.6 (introducing “biased locking” and “lightweight locking”), The performance of synchronized and ReentrantLock is basically equal. ReentrantLock offers more functionality than synchronized, but not necessarily better performance, so synchronized is preferred for synchronization where it can fulfill the requirements

Lock optimization see Java Synchronized (2) lock optimization

summary

  • Characteristics of synchronized: ensure the visibility of memory, atomicity of operation, order of code execution
  • Reasons that synchronized affects performance:
    1. The lock unlocking operation requires additional operations
    2. The biggest performance impact of mutex synchronization is the implementation of blocking, because the suspension and recovery operations involved in blocking need to be carried out in the kernel state (the performance cost of switching between user and kernel state is relatively high).



References:

Zhihu – Summary of Java Synchronized principle

Simple book – A low-level implementation of Synchronized in Java