Welcome to the fifth article in a series on Concurrency.

In the previous article, “Bronze 4: A Primer on Synchronized,” we mentioned the concept of locking and pointed out that synchronized is an implementation of the locking mechanism. However, this is so abstract that you may not understand intuitively what a lock is. So, this article gives you a rough overview of some of the fundamentals behind synchronized to give you a rough but intuitive idea of locking in Java.

This article is divided into two parts. First, you need to learn about locking in Mark Word, because the information about object locks exists in Mark Word, and second, you need to actually experience the changes in Mark Word using the JOL tool.

First, recognize the lock from Mark Word

As we know, in the HotSpot virtual machine, the storage distribution of an object consists of three parts:

  • Header: consists of Mark Word and Klass Pointer;
  • Instance Data: object member variables and Data;
  • Padding: Aligns the padded bytes. Ignore the Padding for now.

In all three sections, Mark Word in the object header is the focus of this article and the key to understanding Java locks. Mark Word records the runtime data of the object, including:

  • Hash code (identity_hashcode)
  • Age of GC generation
  • Lock status flag
  • A lock held by a thread
  • Thread ID (thread)

So, from the point of view of Mark Word in the object header, a lock in Java is a type of data in the object header. In the JVM, each object has such a lock and is used to control concurrency when multiple threads access the object.

If a thread wants to access an instance of an object, it must own a lock on the object. First, it needs to determine whether an instance of the object has been thread-locked by the Mark Word in the object header. If it is not locked, then the thread will write some tag data in the Mark Word to tell others that the object is mine! If another thread wants to access the instance, it waits until the current thread releases the lock on the object, erasing the data in the Mark Word.

Once a thread has a lock, it can enter multiple times. Of course, when the thread releases the lock, it also needs to perform the same number of releases. For example, if a thread has acquired the lock three times, it must release the lock three times before other threads can continue to access it.

The following table shows the object headers on a 64-bit computer:

|------------------------------------------------------------------------------------------------------------|---------- ----------| | Object Header (128 bits) | State | |------------------------------------------------------------------------------|-----------------------------|---------- ----------| | Mark Word (64 bits) | Klass Word (64 bits) | | |------------------------------------------------------------------------------|-----------------------------|---------- ----------| | unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 | OOP to metadata object | Normal | |------------------------------------------------------------------------------|-----------------------------|---------- ----------| | thread:54 | epoch:2 | unused:1 | age:4 | biased_lock:1 | lock:2 | OOP to metadata object | Biased | |------------------------------------------------------------------------------|-----------------------------|---------- ----------| | ptr_to_lock_record:62 | lock:2 | OOP to metadata object | Lightweight Locked | |------------------------------------------------------------------------------|-----------------------------|---------- ----------| | ptr_to_heavyweight_monitor:62 | lock:2 | OOP to metadata object | Heavyweight Locked | |------------------------------------------------------------------------------|-----------------------------|---------- ----------| | | lock:2 | OOP to metadata object | Marked for GC | |------------------------------------------------------------------------------|-----------------------------|---------- ----------|Copy the code

From the table, you can see three sections of information in the Object Header: Mark Word, Klass Word, and State.

2. Experience the changes of Mark Word through JOL

To get a sense of the Mark Word changes in the Object header, we can use the Java Object Layout (JOL) tool to demonstrate the change. JOL is a great tool for viewing Java memory layouts, so hopefully you’ll remember it.

First, introduce dependencies into the project:

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.10</version>
</dependency>
Copy the code

In the following code, master is the object instance we create, and the locking action is performed in the decreaseBlood() method. So, the object header should change after the lock is called decreaseBlood().

 public static void main(String[] args) {
        Master master = new Master();
        System.out.println("==== before locking ====");
        System.out.println(ClassLayout.parseInstance(master).toPrintable());
        System.out.println("==== locked ====");
        synchronized(master) { System.out.println(ClassLayout.parseInstance(master).toPrintable()); }}Copy the code

The output is as follows:

= = = = = = = = cn before locking. Tao. King. Juc. Execises1. The Master object internals. OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object  header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 int Master.blood 100 Instance size: 16 bytes Space losses: 0 bytes internal + 0 bytes external = 0 bytes total = = = = = = = = cn after locking. Tao. King. Juc. Execises1. The Master object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 48 f9 d6 00 (01001000 11111001 11010110 00000000) (14088520) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 int Master.blood 95 Instance size: 16 bytes Space losses: 0 bytes internal + 0 bytes external = 0 bytes total Process finished with exit code 0Copy the code

As you can see from the result, after the code executes the synchronized method, the object header is printed instead of 01 00 00 00 00 00 00 00 00 00 00 48 f9 d6 00 00 00 00 70 00 00, etc. If nothing else, I’m sure you don’t understand what this means.

So, to make it easier to read, we’ve provided a utility class in the Bronze series, “JOL Formatting Tools,” to make the output more readable. Using the utility class, we adjust the code to:

 public static void main(String[] args) {
        Master master = new Master();
        System.out.println("==== before locking ====");
        printObjectHeader(master);
        System.out.println("==== locked ====");
        synchronized(master) { printObjectHeader(master); }}Copy the code

The output is as follows:

==== # WARNING: Unable to attach Serviceability Agent. You can try again with zoomed privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope Class Pointer: 11111000 00000000 11000001 01000011 Mark Word: hashcode (31bit): 0000000 00000000 00000000 00000000 age (4bit): 0000 biasedLockFlag (1bit): 0 LockFlag (2bit): 01 ==== after locking ==== Class Pointer: 11111000 00000000 11000001 01000011 Mark Word: javaThread*(62bit,include zero padding): 00000000 00000000 01110000 00000000 00000100 11100100 11101001 100100 LockFlag (2bit): 00Copy the code

You see, this way, the result of the output is clear. From the lock result, you can see that Mark Word has changed and the current thread has acquired the lock of the object.

So here’s the rationale behind synchronized. Of course, this is only part of the story. For the sake of space and difficulty, this article will not describe the meaning and escalation of locks in Java object headers until later in the article.

That’s all the text. Congratulations on getting another star ✨

The teacher’s trial

  • Download the JOL tool and experience the use of the tool and the changes in the object information in the code.

Further reading and references

  • “King concurrent course” outline and update progress overview

About the author

Pay attention to [technology 8:30], get the article updates in time. Pass on quality technical articles, record the coming-of-age stories of ordinary people, and occasionally talk about life and ideals. 8:30 in the morning push author quality original, 20:30 in the evening push industry depth good article.

If this article is helpful to you, welcome to like, follow, supervise, we together from bronze to king.