preface

Thread concurrency series:

Thread State Java Thread State Java Thread State Java Thread State Java Thread State Java Thread State Java Thread State Java Thread State Java Thread State Java Thread State Java Thread State Java Thread State Unsafe/CAS/LockSupport Application and principle Java concurrency “lock” nature (step by step to implement the lock) Java Synchronized implementation of mutual exclusion application and source exploration Java object header analysis and use (Synchronized related) Java The evolution process of Synchronized partial lock/lightweight lock/heavyweight lock Java Synchronized principle of heavyweight lock in depth (mutual exclusion) Java Synchronized principle of heavyweight lock in depth (synchronization) Java concurrency AQS In-depth analysis (on) the Java concurrency of AQS deep parsing (under) Java Thread. Sleep/Thread. Join/Thread. The yield/Object. Wait/Condition. Await explanation of Java concurrency Already the thorough analysis of concurrent Java (with Synchronized difference) Java Semaphore/CountDownLatch/CyclicBarrier ReentrantReadWriteLock in-depth analysis Deep parsing (principle), Java Semaphore CountDownLatch/CyclicBarrier in-depth analytical (application), the most detailed graphic analytic Java various locks (ultimate) thread pool will understand series

As we learned from the previous article, synchronized modifiers end up working on the head of an object, so the object head is the basis for a deeper understanding of synchronized lock variations. Let’s dive into the role of object headers in synchronized. Through this article, you will learn:

1, object in memory constitute 2, object header constitute 3, object header source code implementation 4, debugging view object header

1. Structure of objects in memory

Let’s start with a simple class:

class Student { int age; String name; } // instantiate the object Student Student = new Student();Copy the code

We know that the new object is placed in the heap, and the structure of the object in the heap is as follows:

It is divided into three parts: object header, instance data (age/name), and padding byte.

2. Object header composition

Partition of object headers

The object header fields are as follows:

Only array objects have an array length part, so let’s use ordinary objects as an example.

Klass Word points to the metadata of the class to which the object belongs.

The size of the object header

For a 64-bit machine, the object header size is as follows:

It can be seen that the header size of an ordinary object is 128bits, while Mark Word and Klass Word occupy 64bits respectively.

Mark Word form

There are differences between 32-bit machines and 64-bit machines. Taking 64-bit as an example, each area of Mark Word is organized as follows:

As you can see above, the Mark Word can represent five states, and only one state at a time. How do I determine what state Mark Word is in? The different bits in the Mark Word content area store different information. You can see that the five states have one message in common: lock. Lock takes up 2bits and can represent four states:

The Mark Word has five states. The value of non-lock and biased lock is the same. How to distinguish between them? You can see that both have the same bit of information: biASed_lock. Biased_lock occupies 1bit and can distinguish between two states:

1——> indicates a biased lock. 0——> indicates a biased lock

Therefore, the combination of LOCK and biASED_lock (a total of three bits) can represent five states:

1. Mark Word structures do not have different member variables like common Java objects, but are refined down to bits to represent specific values. 2. Thanks to the first design, Mark Word can flexibly represent five states in a limited space, saving memory.

3, object header source code implementation

Mark Word definition

Now that we’ve figured out the Mark Word structure, let’s see how to represent states and switch states in code. As mentioned earlier, the source code for this series of concurrent articles is based on jdk1.8. The source code is at hg.openjdk.java.net/.

MarkOopDesc provides a value() function that returns itself (a pointer to the object) and is forced to uintptr_t. Uintptr_t

For 64-bit machines, the uintprt_t represents an 8-byte unsigned integer. Look again at markOopDesc’s parent class, oopDesc: in the oop. HPP file:

This class contains the Mark Word and Klass Word(combination), with a special focus on the markOop type: oopsHierarchy. HPP file.

Mark Word status check

Now that we have the Mark Word memory value (64bits unsigned integer), we can do some work on that value. For example, how can we determine whether the Mark Word is unlocked? Returning to the markOopDesc class, this class provides a number of functions to determine whether the state is unlocked:

Consider mask_bits, which is an inline function:

As you can see, you’re essentially doing a bitwise and operation on two parameters. Back to the mark_bits argument, the first argument is the markOop returned by value(), and the second argument is hidden. Biased_lock_mask_in_place = 0x111(7), and unlocked_value is defined as follows:


If the expression markOop & 0x111(7) == 1 is true, it means that Mark Word is in unlocked state. In fact, the corresponding bit of Mark Word is taken out for judgment

Other functions are similar.

4. Debug the view object header

JOL simple to use

Source code is boring and mostly just helps us understand how it works. Sometimes you don’t need to know the details, just the results. Is there a way to know the value of the current object header? So you can tell which state you belong to by the value. JOL(Java Object Layout) Displays information about Java objects, such as Object headers, instance content, and fill data. Reference the tool in Android Studio:

1, in repo.maven.apache.org/maven2/org/… Jar is a jar that can be referenced in Android Studio or, if you are using Java, via Maven

After importing the JOL package, take a look at the simple usage process:

public class TestDemo { public static void main(String args[]) { Object object = new Object(); System.out.println(vm.current ().details())); / / print System object size. Out. Println (ClassLayout. ParseInstance (object). InstanceSize ()); / / print head size System. Out. Println (ClassLayout. ParseInstance (object). HeaderSize ()); / / print object information System. The out. Println (ClassLayout. ParseInstance (object). ToPrintable ()); }}Copy the code

The results are as follows:

The declared object is empty, so there is no instance data in it. You may have noticed that Klass Word is 32bits, but what about 64bits? The reason is that pointer compression is enabled by default on the Java VM. To turn off pointer compression:

-XX:-UseCompressedOops

The re-run results are as follows:

Query the Mark Word status

unlocked

I still haven’t mentioned how to read the lock state, so let’s see. In the above example, the object is not locked, so it should be unlocked. The key is to find the corresponding bit of Mark Word, as mentioned above, 3bits to determine the Mark Word state:

Lightweight lock

public class TestDemo { public static void main(String args[]) { Object object = new Object(); / / print object information System. The out. Println (ClassLayout. ParseInstance (object). ToPrintable ()); synchronized (object) { System.out.println(ClassLayout.parseInstance(object).toPrintable()); } System.out.println(ClassLayout.parseInstance(object).toPrintable()); }}Copy the code

The results are as follows:

Biased locking

Lock -> bias lock -> lightweight lock evolution process, how directly to lightweight lock state? The JVM does not start bias locking immediately, but rather later. The reason is that at the beginning of the competition is very fierce, biased lock cancellation will increase the burden of the system. The delay is 4s and can be found in globals.hpp:

public class TestDemo { public static void main(String args[]) { try { Thread.sleep(4500); } catch (Exception e) { } Object object = new Object(); / / print object information System. The out. Println (ClassLayout. ParseInstance (object). ToPrintable ()); synchronized (object) { System.out.println(ClassLayout.parseInstance(object).toPrintable()); } System.out.println(ClassLayout.parseInstance(object).toPrintable()); }}Copy the code

Note: Object creation here needs to come after delay because biased locking has no effect on generated objects. The results are as follows:


-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0

Used to disable bias lock delay. Here you may be wondering:

After exiting the critical section, why is it still biased locking?

This problem will be analyzed in the next source analysis.

Heavyweight lock

public class TestDemo { static Object object = new Object(); public static void main(String args[]) { new Thread(new Runnable() { @Override public void run() { System.out.println("before get lock in Thread1"); System.out.println(ClassLayout.parseInstance(object).toPrintable()); synchronized (object) { System.out.println("after get lock in Thread1"); System.out.println(ClassLayout.parseInstance(object).toPrintable()); new Thread(new Runnable() { @Override public void run() { System.out.println("before get lock in Thread2"); System.out.println(ClassLayout.parseInstance(object).toPrintable()); synchronized (object) { System.out.println("after get lock in Thread2"); System.out.println(ClassLayout.parseInstance(object).toPrintable()); } } }, "t2").start(); sleep(5000); } } }, "t1").start(); }}Copy the code

Two threads, T1 and T2, are enabled to print objects before and after they acquire the lock. T1 is executed first, then T2 is turned on, and T1 sleeps for 5s. The analysis is divided into several steps: before T1 obtains the lock:

T1 after acquiring the lock:

T2 before acquiring the lock:

After T2 acquires the lock:

At this point, the simple analysis of Java object headers is complete. No lock, biased lock, lightweight lock, heavyweight lock source code analysis.

Reference: jdk1.8 www.cnblogs.com/lusaisai/p/… Cloud.tencent.com/developer/a…

If you like, please like, pay attention to your encouragement is my motivation to move forward

Continue to update, with me step by step system, in-depth study of Java/Android