JAVA high concurrency (JUC) multi-threaded 8-lock explanation

First understand a concept: synchronized locks the resource class where this method is located, that is the object, that is, it is impossible for two threads to enter this resource class at the same time during the same time period. Only one thread is allowed to access the resource class at the same time period. One of the synchronized methods inside!
T1: 1. Standard access, may I print emails or text messages first?
code show as below:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public synchronized void sendEmail() throws Exception {
        System.out.println("----sendEmail");
    }

    public synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }
}

Result: Although sendEmail is executed first, it is actually not necessarily. Depending on the scheduling of the cpu and the way it is modified by synchronized, the locked object is the caller of the method. Because these two methods lock the same object, they are called first Executed first.

T2: The email method is suspended for 4s. May I print the email or SMS first?
code show as below:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }
}

Result: Although sendEmail is executed first (waiting for 4s), and then sendSMS is followed, it is not always true. It depends on the scheduling of the CPU and the way it is modified by synchronized. The locked object is the caller of the method, because these two methods are locked It is the same object, so the first call is executed first, that is, after 4s, sendEmail appears, and then sendSMS. It is equivalent to that Wang Xiaopang wants to use the mobile phone to send emails, and Wang Erpang wants to use the mobile phone to send short messages. Wang Xiaopang grabs the phone first. It takes 4s to send emails, so it takes 4s to wait for Wang Xiaopang to finish sending the emails. , Wang Er fat can send text messages.
Comprehensive T1, T2:
Conclusion: If there are multiple synchronized methods in an object, at a certain moment, as long as one thread calls the synchronized method, then other threads can only wait. In other words, there can only be a certain time When a thread accesses these synchronized methods, the current object this is locked. After being locked, no other objects can access other synchronized methods of the current object.

T3: Add a common method hello(), may I print the email first or hello? The first hello
code is as follows:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
//                phone.sendSMS();
                phone.hello();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }

    public void hello() {
        System.out.println("----hello");

    }
}

Result: The result is to print hello first, and then sendEmail 4s later, because hello is not modified by synchronized.
Conclusion: The normal method has nothing to do with synchronization locks.

T4: Two mobile phones, may I print emails or text messages first?
code show as below:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
//                phone.sendSMS();
//                phone.hello();
                phone1.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }

    public void hello() {
        System.out.println("----hello");
    }
}

Result: print sendSMS of phone1 first, and then print sendmail of phone 4s later, because the resource objects are different.
Conclusion: Two objects are not the same lock.

T5: Two static synchronization methods, the same mobile phone, may I print emails or text messages first?

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
                phone.sendSMS();
//                phone.hello();
//                phone1.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public static synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public static synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }

    public void hello() {
        System.out.println("----hello");
    }
}

Result: Print sendEmail first, then sendSMS after 4s.

T6: Change from one mobile phone to two mobile phones in the previous question. May I print emails or text messages first?
code show as below:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
//                phone.sendSMS();
//                phone.hello();
                phone1.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public static synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public static synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }

    public void hello() {
        System.out.println("----hello");
    }
}

Result: Print sendEmail first, then sendSMS after 4s.
Comprehensive T5, T6:
Conclusion: At this time, the lock is not the object, but the class! That is, phone.class is locked! The template is locked, and Phone phone=new Phone() locks this Phone. Because phone and phone1 are both instance objects of Phone, and the lock is Phone, so when the phone is executing, phone1 has to wait, because the lock is the template.

T7: 1 normal synchronization method, 1 static synchronization method, 1 mobile phone, may I print emails or text messages first?
code show as below:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
//        Phone phone1 = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
                phone.sendSMS();
//                phone.hello();
//                phone1.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public static synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public  synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }

    public void hello() {
        System.out.println("----hello");
    }
}

Result: sendSMS printed first, then sendEmail printed 4s later. Reason: Because sendEmail locks the template (add static), sendSMS locks the class, and the two do not conflict.
T8: 1 normal synchronization method, 1 static synchronization method, 2 mobile phones, may I print emails or text messages first?
code show as below:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
                phone1.sendSMS();
//                phone.hello();
//                phone1.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public static synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public  synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }

    public void hello() {
        System.out.println("----hello");
    }
}

Result: same as T7, sendSMS printed first, then sendEmail printed 4s later. Reason: Because sendEmail locks the template (add static), sendSMS locks the instance object of the template, and it operates on different objects. The two are not in conflict.

Summary:
Synchronization realizes the basis of synchronization:
Every object in java can be used as a lock.
There are three specific manifestations as follows:
1: For ordinary methods, the lock is the current instance object.
2: For static synchronization methods, the lock is the class object of the current class.
3: For the synchronized method block, the lock is the object configured in synchronized brackets.
When a thread attempts to access a synchronized code block, it must first obtain the lock, and must release the lock when it exits or throws an exception.
That is to say, when a non-static synchronization method of an instance object acquires a lock, other non-static synchronization methods of the instance object must wait for the method of acquiring the lock to release the lock before acquiring the lock. If the non-static synchronization method of another instance object and the non-static synchronization method of the instance object use different locks, then there is no need to wait for the non-static synchronization method of the lock that the instance object has acquired to release the lock, and directly acquire themselves Lock.
Object lock and class lock (this/class) are two different objects, so there will be no race conditions between statically synchronized methods and non-static synchronized methods. But once the static method acquires the lock, other static synchronization methods must wait for the method to release the lock before acquiring the lock.

Guess you like

Origin blog.csdn.net/Pzzzz_wwy/article/details/106040391