Understanding of the 8-lock problem between multi-threaded synchronized object locks and static locks

8 lock problem

There are two concerns: the type of lock, and who
locks it. The type of lock: static locks are for objects of all instances of this class, and object locks
are only for the current object. Who is the locker for synchronized关键字? 非静态The method of the static lock is all the methods with synchronizedkeywords and of this kind. For the above two points, when judging, pay attention to: whether it is the same object, and what kind of lock type is the method called by the object静态

Lock 1: Multiple threads use the same object to call different non-static methods with the synchronized keyword

Analysis: The object lock is only for the current object, and the lock is for all non-static methods with the synchronized keyword.

public class Application {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Phone phone = new Phone();
        new Thread(()->{
    
    phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    phone.sendCall();},"B").start();
    }
   }
class Phone{
    
    
    synchronized void sendSMG(){
    
    
        System.out.println("发送消息");
    }
    synchronized void sendCall(){
    
    
        System.out.println("打电话");
    }
}

Result:
insert image description here
Thinking 1: 为什么A线程与B线程之间启动要睡一会?
The code is executed sequentially, but the operating system can decide when the thread starts. Although A enters the ready state first, the operating system may choose B to start first. Let the A thread and the B thread sleep for a while when they start, to ensure that the A thread must start first. Because the processing of the operating system is extremely fast, even if the interval is 1s, there will be a large time difference for the operating system. Because A and B are not together, A has a great probability to start first.

Thinking 2: 为什么结果是这样?
Two key points:
it is the same object, and the lock type is the same
. A thread starts first and gets the object lock. The object lock will be released), and the method with the synchronized object lock cannot be called, and can only wait. Until the A thread finishes executing and releases the lock, the B thread can acquire the lock and continue to execute.

Thinking 3: 既然sendSMG()方法先执行,如果在方法中睡一会,sendCall()方法会不会先执行?
As mentioned earlier, thread A first executes the sendSMG() method after obtaining the lock, because sleep() in the method will not release the lock, even if the execution time is too long, the lock will not be released before the execution is completed, B You can't get the lock to execute the method with synchronized object lock.
Thinking 4: 如果Phone有一个普通方法,没有带synchronized锁,B线程启动后即使sendSMG()方法没有执行完毕,这个普通方法会被执行吗?
There is no object lock in the ordinary method, and B does not need to wait for A to release the lock when executing, so it can be executed immediately as long as B starts. If thread A also calls this common method, then both threads A and B may be in this method at the same time.

Lock 2: On the basis of lock 1, increase the execution time of the method executed by thread A, so that B has the opportunity to participate in the execution

To verify the above thinking 3, it proves that the sendSMG() method is executed first, not that the A thread starts the execution first, and catches up with the problem that the B thread calls the sendCall() method, but A does not execute the sendSMG() method to release the object lock, and B There will simply not be a chance to execute the sendCall() method. Because the B thread starts after a certain period of time, the object lock is obtained by A first. As long as the lock is obtained, within an object, multiple threads can only have one thread to execute the method with the synchronized object lock.

public class Application {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    

        Phone phone = new Phone();
        new Thread(()->{
    
    phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    phone.sendCall();},"B").start();
    }
}

class Phone{
    
    
    synchronized void sendSMG(){
    
    
        try {
    
     TimeUnit.SECONDS.sleep(2); // 注意:我这里特意为2s使得这是B线程一定启动了 测试:B线程的sendCasll方法会不会先执行。} catch (InterruptedException e) {
    
    }
        System.out.println("发送消息");
    }
    synchronized void sendCall(){
    
    
        System.out.println("打电话");
    }
}

The code just increases the execution time of sendMsg() on the basis of lock 1. The result is the same as lock 1. After waiting for 1 second, the console will display "send message", and then "call" will appear.
insert image description here
Thinking: what will happen?
insert image description here
After thread A grabs the object lock, it executes the sendSMG() method, outputs "send message" on the console, then sleeps for 1s, and releases the lock. Thread B gets the lock, executes the sendCall() method, and immediately outputs "call" on the console

Lock 3: Multiple threads use the same object, one thread executes a method with an object lock, and one thread executes a normal method

Analysis: The object lock locks the non-static method with synchronized, and the ordinary method no longer locks the scope.
Guess: The ordinary method is not affected by synchronized, whichever thread executes faster can be called first.

public class Application {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    

        Phone phone = new Phone();
        new Thread(()->{
    
    phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    phone.sendHello();},"B").start();
    }
}

class Phone{
    
    
    synchronized void sendSMG(){
    
    
        try {
    
     TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {
    
    }
        System.out.println("发送消息");
    }
    synchronized void sendCall(){
    
    
        System.out.println("打电话");
    }
    void sendHello(){
    
    
        System.out.println("hello");
    }
}

Result:
insert image description here
The execution of thread B does not need to wait for the release of the object lock of thread A, because the ordinary method does not need to acquire the object lock at all.

Thinking: What will happen if A thread also calls the normal method, and then refits the normal method like this?
insert image description here
insert image description here
result:
insert image description here


The above uses the same object to discuss the issue of synchronized object locks, and the following uses 不同objects to discuss the issue of synchronized object locks


Lock 4: Multiple threads use different objects to call different methods with object locks

Analysis: Object lock: only valid for the current object, so it is invalid to use between different objects

public class Application {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    

        Phone phone1 = new Phone();
        Phone phone2 = new Phone();
        new Thread(()->{
    
    phone1.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    phone2.sendCall();},"B").start();
    }
}

class Phone{
    
    
    synchronized void sendSMG(){
    
    
        try {
    
     TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {
    
    }
        System.out.println("发送消息");
    }
    synchronized void sendCall(){
    
    
        System.out.println("打电话");
    }
    void sendHello(){
    
    
        System.out.println(Thread.currentThread().getName()+"进入");
        try {
    
     TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) {
    
     }
        System.out.println("hello");
        System.out.println(Thread.currentThread().getName()+"离开");
    }
}

Result:
insert image description here
Thinking: 明明A线程先启动获取了对象锁,为什么B线程的方法在A线程没有执行完毕就开始执行?
There are two concerns: the type of lock and who is locking it.
Threads A and B use different objects, so it is invalid for object locks! The object operated by thread B has its own lock of thread B, and the object operated by thread A has its own lock of thread A. The two are not the same object, so the locks are different. For methods that execute object lock types, the object lock of thread A cannot lock the object lock of thread B
Thinking: 如果锁住不同对象的?
At this time, class locks must be used, because different objects are also instantiated from the same class, and class locks can be used , generating a lock that is also recognized by different objects.


The static lock will be introduced below


Lock 5: Multiple threads call methods on their respective static locks on the same object

Analysis: Static locks, all objects of this type are valid. Locked is a static method with synchronized

public class Application {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    
        Phone phone = new Phone();
        new Thread(()->{
    
    phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    phone.sendCall();},"B").start();
    }
}

class Phone{
    
    
     synchronized static void sendSMG(){
    
    

        try {
    
     TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {
    
    }
        System.out.println("发送消息");
    }
     synchronized static void sendCall(){
    
    
        System.out.println("打电话");
    }
}

Effect:
insert image description here
Adding static to the method is equivalent to the same class lock, no matter whether it is the same object or not, as long as it is an instantiated object of this type, no object can execute until the object acquires the lock and releases it method with class lock

Lock 6: Multiple threads and multiple objects call methods on their respective static locks

The effect is the same as that of lock 5. In methods that are all class locks, it will not distinguish whether they are the same object. As long as an object is executing, whether it is the same object or not, it can only wait to execute the method with a class lock in this class.
Thinking: 如果线程A使用对象1调用的是静态锁方法,线程B使用对象2调用的是普通方法,A先启动,那么对象2调用普通方法是需要等待A释放静态锁吗?
Of course not, because ordinary methods have no locks at all, and class locks cannot limit it


The following mixes static locks with object locks


Lock 7: Multiple threads call the object lock method and the static lock method respectively on the same object

Analysis: There are object locks and static locks, and there is no relationship between them.
Or pay attention to two key points: Is it the same object? Yes; is the method called the same lock type? 不是, one is a static lock, the other is an object lock;
two different methods, because the types of locks are different, there is no relationship between them

public class Application {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    

        Phone phone = new Phone();
        new Thread(()->{
    
    phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    phone.sendCall();},"B").start();
    }
}

class Phone{
    
    
    synchronized void sendSMG(){
    
    

        try {
    
     TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {
    
    }
        System.out.println("发送消息");
    }
    static synchronized void sendCall(){
    
    
        System.out.println("打电话");
    }
}

Effect:
insert image description here
Thread A executes first, but thread A obtains an object lock. After thread B starts, it obtains a class lock, which cannot be locked by an object lock, so B does not have to wait for A to finish executing and release the class lock before going implement.

Thinking 1: 如果是两个线程调用的同一个方法加上静态锁呢?
This has nothing to do with whether it is the same object or not, because locking on a static method is a class-level lock, no matter whether it is the same object or not, as long as one thread acquires the lock, before the lock is released after execution, No other thread can execute this method. But other non-static locking methods can be implemented.

Thinking 2: 如果A先拿到类锁,B后拿到对象锁,那B用等到A释放锁后再去执行吗?也就是说类锁与对象锁是否有包含关系?(different objects)
insert image description here

Proof: class locks and object locks are two types of locks with different scopes (object locks are only for the current object, and class locks are for objects of all instances of this class), but not class locks include object locks

Lock 8: Different objects of multiple threads call the method of object lock and the method of static lock respectively

Same as lock 7 thinking 2, what thread A gets is the object lock belonging to this object 1, and what thread B gets is the class lock belonging to all objects. The types of locks used by the two calling methods are different. Whoever executes faster will output first, and there is no problem of waiting.

Guess you like

Origin blog.csdn.net/m0_52889702/article/details/128847416