In multithreaded programming, multiple threads may access the same shared, variable resource at the same time. We call this resource a critical resource; this resource may be: objects, variables, files, etc.
- Sharing: Resources can be accessed by multiple threads at the same time
- Variable: the resource can be modified during its life cycle
Questions that arise:
Because the process of thread execution is uncontrollable, it is necessary to use a synchronization mechanism to coordinate access to the variable state of the object
Locking role and lock definition classification
Locking purpose: serialized access to critical resources, that is, only one thread can access critical resources at the same time (synchronous exclusive access)
Detailed explanation of synchronized principle
Synchronized built-in lock is an object lock (the lock is an object instead of a reference), and the granularity is the object. It can be used to achieve synchronized and mutually exclusive access to critical resources and is reentrant.
- Synchronous instance method, the lock is the current instance object
- Synchronous class method, lock is the current class object, static method
- Synchronous code block, the lock is the object inside the brackets
The underlying principle of synchronized
Synchronized is implemented based on the JVM built-in lock, implemented by the internal object Monitor (monitor lock), based on the entry and exit of the Monitor object implementation method and code block synchronization, the implementation of the monitor lock depends on the implementation of the Mutex lock (mutual exclusion lock) of the underlying operating system , It is a heavyweight lock with lower performance. Of course, JVM built-in locks have made major optimizations after version 1.5, such as Lock Coarsening, Lock Elimination, Lightweight
Locking, Biased Locking, Adaptive Spinning (Adaptive Spinning) and other technologies to reduce the overhead of lock operations, the concurrency performance of the built-in lock has been basically the same as that of Lock. After the synchronized keyword is compiled into bytecode, it will be translated into two instructions, monitorenter and monitorexit, at the start and end positions of the logic code of the synchronization block respectively.
Each synchronization object has its own Monitor (monitor lock), the locking process is shown in the figure below
The lock state is recorded in the object header (Mark Word) of each object. Let’s take a look at the memory layout of the object.
- Object header: such as hash code, age of the object, object lock, lock status flag, bias lock (thread) ID, bias time, array length (array object), etc.
- Instance data: when the object is created, the member variables, methods, etc. in the object
- Alignment padding: The size of the object must be an integer multiple of 8 bytes.
The expansion and upgrade process of the lock
After JDK1.6, various optimizations have been made to the implementation of synchronized, such as spin locks, biased locks, and lightweight locks.
And turn on the bias lock by default
Turn on the bias lock: -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
Turn off the biased lock: -XX:-UseBiasedLocking
There are a total of four lock states, unlocked state, biased lock, lightweight lock and heavyweight lock. With the competition of locks, locks can be upgraded from biased locks to lightweight locks, and then upgraded heavyweight locks, but the upgrade of locks is one-way, which means that it can only be upgraded from low to high, and there will be no locks. Downgrade. The following picture shows the whole process of lock upgrade:
Note: Synchronized is reentrant. As the lock is upgraded, the optimization is relatively high. Compared with the lock of juc, the optimization space of synchronized is larger.
Must the object be allocated in the heap?
Not necessarily, if no object escape occurs, the object will be allocated on the stack
Coarsening of the lock
There are locks in the following 4 steps, and a total lock will be added after optimization
public void test1(){
//jvm的优化,锁的粗化
stb.append("1");
stb.append("2");
stb.append("3");
stb.append("4");
}
Elimination of locks
public void test2(){
//jvm的优化,JVM不会对同步块进行加锁
synchronized (new Object()) {
//伪代码:很多逻辑
//jvm是否会加锁?
//jvm会进行逃逸分析
}
}