Let’s look at the symptoms: First we define a resource class with two statically synchronized methods and two non-statically synchronized methods

Class People{// Synchronized void eat(){try {timeunit.seconds. Sleep (3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"=eat"); } // Synchronized void drink() {system.out.println (thread.currentThread ().getname ()+"=drink"); } // staticEat synchronized static void staticEat(){try {timeunit.seconds.sleep (4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"=staticEat"); } // staticDrink synchronized static void staticDrink() { System.out.println(Thread.currentThread().getName()+"=staticDrink"); }}Copy the code

Two threads, calling different non-statically synchronized methods of a shared object

static People zhang = new People(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { zhang.eat(); } },"A"); Thread thread2 = new Thread(new Runnable() { @Override public void run() { zhang.drink(); } },"B"); thread1.start(); Timeunit.seconds.sleep (1); thread2.start();Copy the code
// Print simultaneously after 3 seconds (B thread blocked) A=eat B=drinkCopy the code

The results show that different non-static methods on the same object can be blocked by other non-static methods.

Two threads, one static, one non-static, call different synchronized methods on a shared object

static People zhang = new People(); Thread thread1 = new Thread(new Runnable() {@override public void run() {zhang.eat(); } },"A"); Thread thread2 = new Thread(new Runnable() { @Override public void run() { zhang.staticDrink(); } },"B"); thread1.start(); Timeunit.seconds.sleep (1); thread2.start();Copy the code

Print result:

// Print B=staticDrink // Print A=eat after 3 secondsCopy the code

The results show that the invocation of static methods on the same instance object will not be blocked by non-static methods.

As you can see from the above two examples, there is no relationship between static methods and non-static methods for locking. By extension, class attributes and instance attributes are parallel in locking.

Of course, there are many other combinations to verify the scope of the two locks, such as: using two different instances, respectively using the object lock and the class lock, using the same instance using the class lock, etc., this can be verified again, I will not enumerate here.

Object lock:

Synchronized modifies non-static methods and synchronized(this) are object locks. A class can have many objects, so many object locks can be created.

According to the same object, a class can have multiple methods are synchronized, one of the methods by thread to visit and hold the lock, then other methods will also be locked, other threads to access other synchronization method, also is not allowed, because it is locked this class object, no need to go through this object access synchronization events, They’re all blocked.

If there are multiple class objects, different threads will use the lock of different class objects, then the lock will be meaningless, and there will be the problem of thread safety. We can ensure that there is only one class object in the system through singleton to ensure thread safety.

Object composition: Since object locking locks objects, we need to have a general understanding of the elements of objects in Java. So what are the components of objects?

  • Object header: Consists of two parts. The first part is used to store the runtime data of the object itself, that is, the MarkWord has hash code, generation age, lock flag, bias thread ID, bias timestamp and other information.
Store content Lock flag bit The lock state
Object hash code, age generation 01 unlocked
A pointer to a lock record 00 Lightweight locking
Pointer to a heavyweight lock 10 Swell (heavyweight lock)
empty 11 The GC tag
Bias lock thread ID, bias timestamp, object age generation 01 Can be biased

The other part is the pointer type, which is a pointer to an object’s class metadata that the virtual machine uses to determine which class the object is an instance of.

  • Instance data: Instance data contains various member variables of the object, including primitive and reference types, and static properties are placed in Java /lang/Class instead of instance data
  • Alignment padding: The padding area is the padding of a memory address to make an object multiple of 4 bytes if the total size of the object is not an integer multiple.

Now that we know the composition of objects, we can analyze what happens when we lock an object. If you look at the markWord of the object header, you can see that in addition to the lock state, there are also lightweight locks, bloat, and bias.

The state of the lock

There are four types of lock states: unlocked, biased, lightweight, and heavyweight. As locks compete, locks can be upgraded from biased locks to lightweight locks to heavyweight locks (but locks are upgraded in one direction, meaning they can only be upgraded from low to high, with no lock degradation).

– Bias lock:

The author of HotSpot found through research that in most cases, locks are not only not contested by multiple threads, but are always acquired by the same thread multiple times, and biased locks are introduced to make the cost of lock acquisition lower. When a thread, when accessing a synchronized block and obtain the lock will lock in the head and stack frame object record store to lock in the thread ID, after this thread synchronization block on the entry and exit for CAS operation is not needed to lock and unlock, simply test object head Mark in the Word is stored with biased locking points to the current thread. If the test succeeds, the thread has acquired the lock. If the test fails, you need to test again whether the Mark of biased lock is set to 1 (indicating that it is currently biased lock) : If not, CAS is used to compete for the lock. If set, try using CAS to point the bias lock of the object header to the current thread.

When a thread accesses an object and obtains the lock, it stores the ID of the thread to which the lock is biased in the object header. When the thread accesses the object again, it only needs to check whether the ID of the thread exists in the Mark Word of the object header. If so, no CAS operation is required. Biased locks are upgraded to lightweight locks as thread contention becomes more intense

– Lightweight lock:

Before a thread executes a synchronized block, the JVM creates space to store the lock record in the stack frame (the unit in the virtual machine stack) of the current thread, copies the Mark Word in the object header into the lock record, and then attempts to replace the Mark Word in the object header with a pointer to the record using CAS. If it succeeds, the current thread acquires the lock; if it fails, other threads are competing and the current thread uses spin to acquire the lock.

Lightweight lock think although competition exists, but ideally the level of competition is very low, wait for a while by spin on a thread can lock is released, but when the spin over a certain number of times, or a thread holds a lock, a thread in the spin, again the third interview with thread (anyway is the competition continues to increase), Lightweight locks inflate to heavyweight locks

– Heavyweight lock

A heavyweight lock relies on the internal monitor lock, which in turn relies on the operating system MutexLock, so it is also called a mutex.

When the system detects that the lock is a heavyweight lock, it blocks the thread waiting to acquire the lock. The blocked thread does not consume CPU. But blocking or waking up a thread requires the operating system to help, and that requires switching from user to kernel, which takes a lot of time, perhaps longer than the user executes the code.

Comparison of three states of locks
The lock advantages disadvantages scenario
Biased locking Locking and unlocking require no additional cost, with a nanosecond difference compared to implementing asynchronous methods If there is contention between threads, there is additional lock cancellation cost This applies to scenarios where only one thread accesses a synchronized block
Lightweight lock Competing threads do not block, improving thread response speed Using spin consumes CPU if the lock is never contested Pursuit of response time, synchronous block execution speed is fast
Heavyweight lock Thread contention does not use spin and does not consume CPU Threads are blocked and response time is slow Throughput pursuit, synchronous block response time is long

Say so many, we should know that to lock objects, what has changed, by Mark Word tag and lock lock in the state of change, to identify that the current state of the object, when we use synchronized methods to query the state, and according to the environment of the current thread, used to determine what kind of strategy to deal with.

Kind of lock:

Synchronized static or synchronized(class) locks are class locks. Class information is stored in the JVM method area, and the entire JVM has only one copy. The method area is shared by all threads, so class locks are shared by all threads.

Two threads, calling statically synchronized methods of two objects

Static People wang = new People(); Static People zhang = new People(); Thread thread1 = new Thread(new Runnable() {@override public void run() {zhang.staticEat(); } },"A"); Thread thread2 = new Thread(new Runnable() { @Override public void run() { wang.staticDrink(); } },"B"); thread1.start(); Timeunit.seconds.sleep (1); thread2.start();Copy the code

Results:

// Print A=staticEat B=staticDrink after 4 secondsCopy the code

As you can see, even with different instances, calling different static methods, the result is still blocked. Class locking is object – insensitive.

Above is my understanding of class lock and object lock, if there is any mistake, please also point out, thank you.