Simply understand the selection of synchronized code block lock object

Posted by campsoup1988 on Wed, 05 Jan 2022 21:28:26 +0100

Simply understand the selection of synchronized code block lock object

1. Readme

Let me briefly explain my understanding:

The selection of this lock object should meet one of the most basic conditions: uniqueness.

We can imagine that the function of this lock is to lock resources (that is, lock the data information operated by the current thread). If the content of this lock changes, the content of the same lock will be different at different times. As a result, this lock is inconsistent and has no uniqueness. The specific explanation is combined with the following figure:

I describe the process in a simple way:

1. Thread 1 and thread 2 both grab the cpu time slice. Now thread 1 gets it, but thread 2 doesn't. once the thread executes the task, thread 2 stops there to grab the next cpu time slice.

2. As soon as the thread executes the task to the code block, it will formulate a flag according to the lock you give (that is, to an object). The function of this flag is: when the thread operates the code inside the code block, the whole code block resources are not open to the outside world (that is, other threads can't touch this resource). You can imagine that ha, this code block is a room, The lock is the door lock of the room. The data involved in the code executed in the code block is the things of the room.

3. When the task of thread 1 is half executed and the time slice runs out, thread 1 and thread 2 compete for the cpu time slice.

4. As soon as the thread is snatched, the thread will continue to execute the task (as soon as the thread is half executed, the record when there is no time slice starts to continue). Since the thread has a lock for the first time, the thread will take the lock generated now and compare it with the previous lock. As a result, as soon as the thread has something to open the lock, it will enter the room to continue to execute the task.

5. If thread 2 grabs, thread 1 stops there to grab the next cpu time slice. When thread 2 executes the code block, a lock will be generated. This lock will be compared with the lock created by thread 1 before: if the lock is different, thread 2 can directly replace the previous lock and enter the room with its own lock for task execution; If the lock is the same, thread 2 needs thread 1 to unlock the key, but thread 2 doesn't have this key. He can't open the lock and enter the room, so he can't perform the task.

6. Whether thread 2 executes the task or not, when the time slice runs out, he grabs the time slice with thread

2. Look at the code running results

(unlocked) task code executed:

public class Run implements Runnable{
    private int i=0;
    //Set variable lock
    String nn=new String();
    //Set unique locks
    final int ff=0;
    @Override
    public void run() {
        int j=0;
        //The current nn string object is a variable lock
        synchronized (nn){
            //To complete a task, a thread needs to execute the following steps 10 times
            while (j < 10) {
                //Record which thread is currently doing
                System.out.println(i + "    Current thread name:" + Thread.currentThread().getName());
                i++;
                j++;
                //Set a new value to make it a variable lock
                nn="sd"+nn;
            }
        }
    }
}
public class Run implements Runnable{
    private int i=0;
    //Set variable lock
    String nn=new String();
    //Set unique locks
    final int ff=0;
    @Override
    public void run() {
        int j=0;
        //Every time the new object address changes, it cannot be locked
        synchronized (new Object()){
            //To complete a task, a thread needs to execute the following steps 10 times
            while (j < 10) {
                //Record which thread is currently doing
                System.out.println(i + "    Current thread name:" + Thread.currentThread().getName());
                i++;
                j++;
                //Set a new value to make it a variable lock
                nn="sd"+nn;
            }
        }
    }
}

Thread test code:

public class ThreadTest {
    public static void main(String[] args) {
        Run run=new Run();
       Thread thread=new Thread(run,"1");
       Thread thread1=new Thread(run,"2");
       Thread thread2=new Thread(run,"3");
        thread.start();
        thread1.start();
        thread2.start();
    }
}

Test results: it can be seen that the resources are not locked at all. During the execution of thread 1, thread 2 and thread 3 modify the resource data. Thread 1 just reads the resource data (I use int i here as the resource data), the time slice runs out. Thread 2 grabs the time slice, and thread 2 will get the resource data and execute the I + + operation. After the time slice runs out, As soon as thread 1 grabs the time slice, thread 1 gets the value before thread 2 executes. On this basis, it executes I + +. Therefore, the value of two I's below will be 6, which also explains why the value of 7 is after 13.

After changing the lock for executing a task to a unique lock:

public class Run implements Runnable{
    private int i=0;
    //Set variable lock
    String nn=new String();
    //Set unique locks
    final int ff=0;
    @Override
    public void run() {
        int j=0;
          //At present, ff this int is a basic data type. It needs to be encapsulated as int object data. It is a unique lock
        synchronized ((Integer)ff){
            //To complete a task, a thread needs to execute the following steps 10 times
            while (j < 10) {
                //Record which thread is currently doing
                System.out.println(i + "    Current thread name:" + Thread.currentThread().getName());
                i++;
                j++;
                //Set a new value to make it a variable lock
                nn="sd"+nn;
            }
        }
    }
}

Execution result: it can be found that thread 2 and thread 3 are not interspersed in thread 1. This shows that when thread 2 and thread 3 execute before thread 1 is completed, the lock has not been opened at all, that is, the i + + operation that has not touched the i value has not been touched until the lock is unlocked after thread 1 executes. When thread 2 executes, it creates the lock again. He has the key, Thread one and thread three can't unlock.

Summary:

In my opinion, the lock here should be unique to successfully lock resources;

Uniqueness judgment: as long as the address of the object does not change, it will be unique;

for instance:

Our common locks are

this: refers to my current task object. Since the object is created only once, the address is unique and resources can be locked;

Object.class: This is the template class of the object class. In the jvm class loading mechanism of Java, we know that the class is loaded only once, so this class object is unique and can also be locked;

new Object().getClass(): this and the object above The reason is the same.

Finally, I hope my understanding can help you. If I have any mistakes, please give me some advice and make progress together

Topics: Java Back-end