Say what I said before

As I said at the beginning, I’m going to put together some Java concurrent programming learning documents, and this is the third installment: the synchronized keyword.

Mainly about the use of synchronized keyword, lock principle, lock re-entry, dirty read, lock upgrade and other problems.

Welcome to follow and like.

Lat‘s go

Dirty read

Let’s start with a concept: dirty reading.

Dirty data is read.

What is dirty data?

Dirty data is meaningless or uncertain data.

Dirty reads occur when one thread reads data that another thread is modifying but hasn’t finished modifying.

As if: flower and boyfriend uncomfortable, then Xiaoming take advantage of the opportunity, and flower ogling, Xiaoming thought he was the boyfriend of the flower, but flower night back and boyfriend serious discussion of some problems, immediately made up. Then xiao Ming’s thought in his heart is meaningless. The idea is dirty.

Ok, let’s look at an example:

package com.st.sync;

import java.util.concurrent.TimeUnit;

/ * * *@authorProgrammers in wigs@companyJiangsu Ji engraved knowledge - starting point programming */
public class SyncDemo0 {
    // Here are the ideas stored like flowers
    private static String info = "Flower loves her boyfriend.";
    public static void main(String[] args) {
        // Thread 1, which represents the change of ideas such as flowers themselves
        new  Thread(()->{
            System.out.println("Flower's first thought:"+info);
            // Things start to get ugly
            info = "This boyfriend is really not very good......";
            // Start thinking about the problem
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // After discussing some problems with her boyfriend
            info = "This boyfriend line of time or quite good......";
        }).start();
        // Thread 2, indicating xiao Ming to read the thoughts of Ruhua
        new Thread(()->{
            // Xiaoming read the thoughts of flowers
            System.out.println("What Xiao Ming saw:"+info);
            // Xiao Ming and flower in the ambiguous
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("The last thing Xiao Ming saw:"+info); }).start(); }}Copy the code

Results:

In this case, the idea Ming sees for the first time is dirty idea, dirty data. Since the thread of ruhua is still modifying the idea, the idea data read by Xiaoming during the modification process is uncertain. It doesn’t make sense.

This is known as dirty reads, and in the example above you can prevent dirty reads by using the synchronized keyword. The next section discusses the synchronized keyword.

Synchronized is what? How to use?

The synchronized keyword locks code (resources).

What do you mean locked?

Locking is locking. When you go to the bathroom, you lock the door for safety or to avoid embarrassment, and you have the bathroom all to yourself. So, locking is locking.

A lock in a program is a lock on some resource or code. After the lock, the resource function is used by the current thread, and other threads have to carry it. Lock it up.

Synchronized is an object that is locked, and it depends on the situation. ** How to lock objects is covered in a later section.

If you want to know how to use it, take a look at this example:

** Case 1:** Synchronize static methods.

If a synchronized static method modifies synchronized, the Class object of the method’s Class is locked when the method is executed. Other threads are unable to execute any synchronized static methods in the current class. Of course instance methods can be executed.

Serving:

package com.st.sync;

import java.util.concurrent.TimeUnit;

/ * * *@authorProgrammers in wigs */
public class SyncDemo {
    public static void main(String[] args) {
        Thread 1, execute synchronous static method 1
        new Thread(()->{
            try {
                method1();
            } catch (InterruptedException e) {
            }
        }).start();
        Thread 2, execute synchronous static method 2
        newThread(()->{method2(); }).start();// thread 3, execute synchronous non-static methods
        new Thread(()->{newSyncDemo().method3(); }).start(); }// synchronize static method 1
    public synchronized  static void method1(a) throws InterruptedException {
        System.out.println("Synchronous static method 1 begins");
        // Get a little sleep at the beginning
        TimeUnit.SECONDS.sleep(1);
        System.out.println("Synchronous static method 1 ends");
    }
    // synchronize static method 2
    public synchronized  static void method2(a) {
        System.out.println("Synchronous static method 1 begins");
        System.out.println("Synchronous static method 1 ends");
    }
    // Synchronize the instance method
    public synchronized void method3(a){
        System.out.println("Synchronize instance method execution"); }}Copy the code

Execution Result:

It is obvious that the synchronized static method 1 starts and the synchronized instance method does not execute even if it enters a blocking state, but the synchronized static method 2 must wait for the synchronized static method 1 to complete and release the lock on the Class object.

What? Will asynchronous methods be affected? I decline to answer this question because it is outside the scope of concurrent programming…….

** Case 2: ** synchronizes instance methods

If synchronized modifies instance methods, the instance method caller (this) is locked whenever a thread executes a synchronized instance method. Other threads cannot call other synchronized instance methods of this object.

Serving:

/ * * *@authorProgrammers in wigs */
public class SyncDemo1 {
    public static void main(String[] args) {
        // Instance object
        SyncDemo1 sd = new SyncDemo1();
        Thread 1, execute synchronous instance method 1
        new Thread(()->{
            try {
                sd.method1();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        Thread 2, execute synchronized instance method 2
        newThread(()->{sd.method2(); }).start(); }// Synchronize instance method 1
    public synchronized void method1(a) throws InterruptedException {
        System.out.println("Synchronization instance method 1 begins");
        // Take a nap
        TimeUnit.SECONDS.sleep(2);
        System.out.println("Synchronization instance method 1 ends");
    }
    // Synchronize instance method 2
    public synchronized void method2(a){
        System.out.println("Synchronize instance method 2 execution"); }}Copy the code

Results:

Obviously, even if synchronous instance method 1 is blocked, synchronous instance method 2 must wait for instance method 1 to finish before executing. The SD object is locked.

** Case 3: ** Synchronizes code blocks

Synchronizing code blocks is easy to understand. Synchronized {} is the object in ().

Serving:

package com.st.sync;

import java.util.concurrent.TimeUnit;

/ * * *@authorProgrammers in wigs@companyJiangsu Ji engraved knowledge - starting point programming */
public class SyncDemo2 {
    public static void main(String[] args) {
        // Ready to lock the guy
        Object obj = new Object();
        Thread 1, lock obj
        new Thread(()->{
            synchronized (obj){
                System.out.println("Thread 1, obj locked.");
                // Take a nap
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread 1, ready to release OBj.");
            }
        }).start();
        // Thread 2 also locks obj
        new Thread(()->{
            synchronized (obj){
                System.out.println("Scene two, obJ locked."); } }).start(); }}Copy the code

Thread 2 must wait for thread 1 to release obj before it can continue.

Ok, just to summarize:

When synchronized modifies static methods, Class objects are locked.

This object is locked when synchronized modifies instance methods.

When synchronized modifies a block of code, it locks the objects inside ().

What does it mean to lock the object low? Look at the next section.

How does synchronized go low?

Synchronized to low is how to lock the object. Lock the object header. Here’s my explanation:

A Java object is a binary string in memory, which is a string of 01’s. The first part of the string of 01’s is the same structure. In the first part of the structure, the last three bits are the lock flag bits of the object. The so-called lock flag bit means that when the value of the three bits changes, the locked state of the object changes. How to do this is explained in detail in the next section, “Upgrading locks”.

Therefore, to lock this object, it is necessary to try to change the value of the lock flag of this object.

Such as:

Locked state:

Unlock Status:

The so-called lock object is probably like this, should not be difficult to understand it.

Synchronized lock escalation

Synchronized is all about locking. Before JDK1.6, synchronized was a heavyweight lock. It was optimized after JDK1.6 and will automatically upgrade as needed.

What is a heavyweight lock?

The so-called heavyweight lock is when you go to the bathroom and lock the door, your roommate comes to check, lock the door and leave, and then you tell him to go to the bathroom after you use the bathroom.

There is a lightweight lock, which is also optimistic lock. Even if you lock the door when you go to the toilet, you are very anxious and dare not take a single second, so he guards at the door of the toilet, constantly asking: “Are you ready? Are you ready? . “. All you have to do is be good. He rushed to the toilet as soon as he could. (This is reentrant implemented by CAS)

Ok, let’s talk about lock upgrades.

As of JDK1.6, objects are classified as lockless, biased locking, lightweight locking, and heavyweight locking.

That was mentioned in the last section. The last three bits in the object header are the lock identifier bits. This is the general picture.

Lock flag bit The lock state
0 01 Unlocked state
1 01 Biased lock state
1 00 Lightweight lock state
1, 11 Heavyweight lock state

Of course, you can print object headers on the console and see what happens to them. (This is easily done using third-party tools). But it can be a bit tricky for you to see the data change for the lock upgrade. I really didn’t plan to write a test program for lock upgrade in this document today. If you need to leave a message, I will add one.

Here’s how synchronized locks can be upgraded.

The newly created object is unlocked. When a thread is in use, the object becomes locked. It automatically switches to lightweight locks when there is a small amount of contention. Adjust to heavyweight locks when there is more concurrency and contention.

Here’s how I describe it:

  • Without lock state: xiao Ming and flower are just common friends, xiao Ming can not be restricted with a lot of girls ambiguous.

  • Partial lock state: Xiaoming and be like flower determined male and female friend concern, xiaoming and be like flower only ambiguous, and the girl that also does not have other seeks Xiaoming.

  • Lightweight lock: Xiaoming and ruhua clear relationship, but Xiaoming met poetry, Shanshan, Meimei, qian Qian… All of them moved Xiao Ming’s heart. Then such as flower in a rage captured xiaoming crime tool “mobile phone”. But even so, these poems ah, Shanshan ah, Meimei ah, or from time to time to find Xiao Ming.

  • Heavyweight lock: as a result of xiaoming’s glamour, come looking for xiaoming’s all sorts of poems, all sorts of qian Qian too much, such as flower for safety take Xiaoming to get marriage certificate directly. And the world declares that Ming is now her private resource. Response pursuit xiaoming, must wait for her and Xiaoming divorce again.

Sychronized lock upgrades are handled automatically, and this is roughly the case above. If you don’t understand, please ask questions.

Reentrant lock

The so-called lock reentrant is a thread that has acquired a lock and tries to acquire the same lock again for various reasons. This is lock reentrant.

Sychronized is reentrant for locks. The example is very simple. It is an attempt to call a synchronized method from within a synchronized method.

Look at an example:

package com.st.sync;

/ * * *@authorProgrammers in wigs@companyJiangsu Ji engraved knowledge - starting point programming */
public class SyncDemo3 {
    public static void main(String[] args) {
        method1();
    }
    // synchronize static method 1
    public synchronized static void method1(a){
        System.out.println("Synchronous static method 1");
        // Call statically synchronized method 2
        method2();
    }
    // synchronize static method 2
    public synchronized static void method2(a){
        System.out.println("Static synchronization method 2"); }}Copy the code

If we call statically synchronized method 2 in synchronized static method 1, it definitely makes sense. Because both methods are synchronous static, they lock the same object Class object. So when synchronous method 2 is called it is a reentrant of the lock.

So much for synchronized… What else needs to be added to welcome everyone to leave a message…….