Detailed explanation of JAVA multithreading

Posted by stilgar on Thu, 03 Mar 2022 17:04:36 +0100

Detailed explanation of JAVA multithreading (II)

III Thread state

1. Five states


2. Thread method

methodexplain
setPriority(int newPriority)Change the priority of a thread
static void sleep(long millis)Hibernates the currently executing thread for the specified number of milliseconds
void join()Wait for the thread to terminate
static void yield()Pauses the currently executing thread object and executes other threads
void interrupt()Interrupt the thread. Don't do it this way
boolean isAlive()Test whether the thread is active

3. Thread stop

It is not recommended to use the stop() destroy() method provided by JDK [obsolete].
It is recommended that the thread stop by itself
It is recommended to use a flag bit to terminate the variable. When flag= false, the thread will be terminated.

//Test stop
//1. It is recommended that the thread should be stopped normally and the number of utilization times should be increased. Dead loop is not recommended
//2. It is recommended to use the flag bit and set the flag bit
//3. Do not use outdated methods such as stop or destroy, or methods not recommended by JDK
public class TestStop implements Runnable{
   //1. Set a flag bit
   private boolean flag=true;

   @Override
   public void run(){
       int i=0;
       while (flag){
           System.out.println("run..Thread"+i++);
       }
   }

   //2. Set a stop flag of the thread and 2. Set a stop flag of the method
   public void stop(){
       this.flag=false;
   }
   
   public static void main(String[] args) {
       TestStop testStop = new TestStop();
       new Thread(testStop).start();

       for (int i = 0; i < 1000; i++) {
           System.out.println("main.."+i);
           if(i==900){
               //Switch the flag bit to stop the thread
               testStop.stop();
               System.out.println("The thread stopped");
           }
       }
   }
}
---------------Result segment---------------
...
run..Thread1129
run..Thread1130
main..900
run..Thread1131
 The thread stopped
main..901
main..902
main..903
...

4. Thread hibernation

Sleep specifies the number of milliseconds the current thread is blocking
Exception in sleep, InterruptedException;
After the sleep time reaches, the thread enters the ready state;
sleep can simulate network delay, countdown, etc
Every object has a lock, and sleep will not release the lock

Demo: timing:

//Analog countdown
public class TestSleep {
    public static void main(String[] args) {
        try {
            tenDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    public static void tenDown() throws InterruptedException {
        int num=10;
        while (true){
            Thread.sleep(1000);
            System.out.println(num--);
            if (num<=0){
                break;
            }
        }
    }
}
---------------result---------------
10
9
8
7
6
5
4
3
2
1
import java.text.SimpleDateFormat;
import java.util.Date;

//Analog countdown
public class TestSleep {
    public static void main(String[] args) {
        Date startTime = new Date(System.currentTimeMillis());//Get the current time of the system
        while (true){
            try {
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
                Thread.sleep(1000);
                startTime = new Date(System.currentTimeMillis());//Update current time
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
---------------result---------------
Always output the current computer time
09:40:34
09:40:35
09:40:36
09:40:37

5. Comity

Comity thread: pause the currently executing thread without blocking it
Change the thread from running state to ready state
Let the CPU reschedule, comity is not necessarily successful! Look at CPU mood

//Test comity thread
public class TestYield {
    public static void main(String[] args) {
        MyYield myYield = new MyYield();
        new Thread(myYield,"a").start();
        new Thread(myYield,"b").start();
    }
}

class MyYield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"The thread starts running");
        Thread.yield();//Comity
        System.out.println(Thread.currentThread().getName()+"Thread stop execution");
    }
}
---------------result---------------
a The thread starts running
b The thread starts running
a Thread stop execution
b Thread stop execution

6. Thread enforcement - Join

Join merge threads. After this thread completes execution, execute other threads. Other threads are blocked
Imagine jumping in line

//Test Join method
public class TestJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("thread  vip..."+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //Start our thread
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();

        //Main thread
        for (int i = 0; i < 30; i++) {
            if (i==20){
                thread.join();//Jump in line
            }
            System.out.println("main..."+i);
        }
    }
}
---------------result---------------
main...0
main...1
...
main...19
 thread  vip...0
...
thread  vip...19
main...20
...
main...29

7. Thread state observation

Thread. State
Thread state. A thread can be in one of the following states.

NEW
 Threads that have not been started are in this state.
RUNNABLE
 stay Java The thread executing in the virtual machine is in this state.
BLOCKED
 Threads that are blocked waiting for a monitor lock are in this state.
WAITING
 A thread that is waiting for another thread to perform a specific action is in this state.
TIMED WAITING
 The thread that is waiting for another thread to perform the action for the specified waiting time is in this state.
TERMINATED
 The exited thread is in this state.

A thread can be in a state at a given point in time. These states are virtual machine states that do not reflect the state of any operating system thread.

//Observe the status of the test thread
public class TestState {

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("///");
        });
        //Observation state
        Thread.State state = thread.getState();
        System.out.println(state);//new

        //Observe after startup
        thread.start();//Start thread
        state = thread.getState();
        System.out.println(state);//run

        while (state != Thread.State.TERMINATED){  //As long as the thread does not terminate, it will always output the state
            Thread.sleep(700);
            state = thread.getState();  //Update thread status
            System.out.println(state);//Output status
        }
    }
}
---------------result---------------
NEW
RUNNABLE
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
///
TERMINATED

8. Thread priority

Java provides a thread scheduler to monitor all threads that enter the ready state after startup. The thread scheduler determines which thread should be scheduled to execute according to priority.

The priority of threads is expressed in numbers, ranging from 1 to 10
Thread.MIN_PRIORITY= 1;
Thread.MAX_PRIORITY=10;
Thread.NORM_PRIORITY= 5;

Change or obtain priorities in the following ways
getPriority(). setPriority(int xxx)

Priority setting is recommended before start() scheduling

Low priority only means that the probability of obtaining scheduling is low, not that it will not be called if the priority is low, which depends on the scheduling of CPU

//Test thread priority
public class TestPriority{
    public static void main(String[] args) {
        //Default priority of main thread
        System.out.println(Thread.currentThread().getName()+"-->"
                +Thread.currentThread().getPriority());

        MyPriority myPriority = new MyPriority();
        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);

        //Set priority before starting
        t1.start();

        t2.setPriority(1);
        t2.start();

        t3.setPriority(4);
        t3.start();

        t4.setPriority(Thread.MAX_PRIORITY);
        t4.start();
    }
}

class MyPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"
                +Thread.currentThread().getPriority());
    }
}
---------------result---------------
main-->5
Thread-3-->10
Thread-0-->5
Thread-1-->1
Thread-2-->4

Daemon thread

Threads are divided into user threads and daemon threads
The virtual machine must ensure that the user thread has completed execution
The virtual machine does not have to wait for the daemon thread to finish executing
For example, record the operation log in the background, monitor the memory, and wait for garbage collection

//Test daemon thread
public class TestDaemon {
    public static void main(String[] args) {
        God god = new God();
        You you = new You();
        Thread thread = new Thread(god);
        thread.setDaemon(true);//The default is false, which means user thread

        thread.start();//Daemon thread start

        new Thread(you).start();//User thread start
    }
}
class God implements Runnable{

    @Override
    public void run() {
        while (true){
            System.out.println("God is always alive");
        }
    }
}


class You implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("--You're alive--");
        }
        System.out.println("goodbye world");
    }
}
---------------result---------------
When the user thread ends, the virtual machine ends and the daemon thread stops

IV Thread synchronization (key)

Multiple threads operate on the same resource

1. Concurrency

Concurrency: the same object is operated by multiple threads at the same time

2. Thread synchronization

In real life, we will encounter the problem that "many people want to use the same resource". For example, everyone wants to eat in the canteen. The most natural solution is to queue up One by one

When dealing with multithreading, multiple threads access the same object, and some threads also want to modify the object
At this time, we need thread synchronization Thread synchronization is actually a waiting mechanism. Multiple threads need to be accessed at the same time
The thread of this object enters the waiting pool of this object to form a queue, waiting for the previous thread to use up, and then the next thread can use it again

3. Queues and locks

Forming conditions: queue + lock. We need these two things to solve the problem of thread insecurity

4. Thread synchronization

Because multiple threads of the same process share the same storage space, it brings convenience and access conflict. In order to ensure the correctness of data being accessed in the method, the lock mechanism synchronized is added during access. When one thread obtains the exclusive lock of the object and monopolizes resources, other threads must wait and release the lock after use

There are the following problems

  1. Holding a lock by one thread will cause all other threads that need the lock to hang
  2. In multi-threaded competition, locking and releasing locks will lead to more context switching and scheduling delays, resulting in performance problems
  3. If a high priority thread waits for a low priority thread to release the lock, the priority will be reversed
    Set, causing performance problems

5. Three unsafe cases

Case 1:

//Unsafe ticket buying
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();

        new Thread(buyTicket,"Xiao Ming").start();
        new Thread(buyTicket,"I").start();
        new Thread(buyTicket,"cattle").start();
    }
}

class BuyTicket implements Runnable{
    private int ticketNums=10;  //Number of votes
    boolean flag=true;  //External stop mode

    @Override
    public void run() {
        //Buy a ticket
        while (flag){
            buy();
        }
    }
    private void buy(){
        //Judge whether there are tickets
        if (ticketNums<0){
            flag=false;
            return;
        }
        //Analog delay
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"Got it:"+ticketNums-- );
    }
}
---------------result---------------
Xiao Ming got it:10
 Cattle got it:9
 I got it:9
 Xiao Ming got it:8
 Cattle got it:7
 I got it:6
 Xiao Ming got it:5
 I got it:4
 Cattle got it:3
 Xiao Ming got it:2
 I got it:1
 Cattle got it:0
 Xiao Ming got it:-1

Case 2:

//Unsafe withdrawal
public class UnsageBank {
    public static void main(String[] args) {
        Account account = new Account(10000, "Wedding bride price");

        Drawing you = new Drawing(account, 5000, "Xiao Ming");
        Drawing girlFriend = new Drawing(account, 10000, "girl friend");

        you.start();
        girlFriend.start();
    }
}
//account
class Account{
    int money;//balance
    String name;//Card name

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}

class Drawing extends Thread{
    Account account;//account
    int drawingMoney;//How much did you withdraw
    int nowMoney;//How much money do you have

    public Drawing(Account account,int drawingMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
    }
    //Withdrawal operation
    @Override
    public void run() {
        //Judge whether there is money
        if (account.money-drawingMoney<0){
            System.out.println("Insufficient account balance!");
            return;
        }
        //Simulation delay can reduce the occurrence of method problems
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //Card balance = balance - get money
        account.money=account.money-drawingMoney;
        //The money in your hand
        nowMoney=nowMoney+drawingMoney;
        System.out.println(account.name+"Card balance:"+account.money);
        //nowMoney+Thread.currentThread().getName() == this.getName()
        System.out.println(this.getName()+"Money in hand:"+nowMoney);
    }
}
---------------result---------------
Balance in wedding gift card:-5000
 Balance in wedding gift card:-5000
 Money in hand: Xiaoming 5000
 Money in girlfriend's hand: 10000

Case 3:

import java.util.ArrayList;
//Thread unsafe collection
public class UnsafeList {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}
---------------result---------------
9997

6. Synchronization method and synchronization block

  1. Synchronization method

Because we can use the private keyword to ensure that data objects can only be accessed by methods, we only need to propose a mechanism for methods. This mechanism is the synchronized keyword, which includes two usages: the synchronized method and the synchronized block

Synchronization method: public synchronized void method (int args) {}

The synchronized method controls the access to "objects". Each object corresponds to a lock. Each synchronized method must obtain the lock of the object calling the method before it can be executed, otherwise the thread will block. Once the method is executed, it will monopolize the lock until the method returns, and the lock will not be released until the blocked thread can obtain the lock and continue to execute

Defect: declaring a large method synchronized will affect efficiency

Only the contents that need to be modified in the method need to be locked. Too many locks waste resources

  1. Synchronization block

Synchronization block: synchronized(obj) {}
obj calls it a synchronization monitor

obj can be any object, but shared resources are recommended as synchronization monitors
There is no need to specify a synchronization monitor in the synchronization method, because the synchronization monitor of the synchronization method is this, the object itself, or class [explained in reflection]

Synchronization monitor execution process
1. The first thread accesses, locks the synchronization monitor and executes the code therein
2. When the second thread accesses, it is found that the synchronization monitor is locked and cannot be accessed
3. After the first thread is accessed, unlock the synchronization monitor
4. The second thread accesses and finds that the synchronization monitor has no lock, and then locks and accesses it

7. Case modification

After modification of case 1:

//Buy tickets safely
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();

        new Thread(buyTicket,"Xiao Ming").start();
        new Thread(buyTicket,"I").start();
        new Thread(buyTicket,"cattle").start();
    }
}

class BuyTicket implements Runnable{
    private int ticketNums=10;  //Number of votes
    boolean flag=true;  //External stop mode

    @Override
    public void run() {
        //Buy a ticket
        while (flag){
            //Analog delay
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            buy();
        }
    }
    //synchronized synchronization method
    private synchronized void buy(){
        //Judge whether there are tickets
        if (ticketNums<=0){
            flag=false;
            return;
        }
        System.out.println(Thread.currentThread().getName()+"Got it:"+ticketNums-- );
    }
}
---------------result---------------
Xiao Ming got it:10
 Cattle got it:9
 I got it:8
 I got it:7
 Cattle got it:6
 Xiao Ming got it:5
 Xiao Ming got it:4
 Cattle got it:3
 I got it:2
 I got it:1

Case 2 after modification:

//Safe withdrawal
public class UnsageBank {
    public static void main(String[] args) {
        Account account = new Account(10000, "Wedding bride price");

        Drawing you = new Drawing(account, 5000, "Xiao Ming");
        Drawing girlFriend = new Drawing(account, 10000, "girl friend");

        you.start();
        girlFriend.start();
    }
}
//account
class Account{
    int money;//balance
    String name;//Card name

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}

class Drawing extends Thread{
    Account account;//account
    int drawingMoney;//How much did you withdraw
    int nowMoney;//How much money do you have

    public Drawing(Account account,int drawingMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
    }
    //Withdrawal operation
    @Override
    public void run() {
        //Locked shared resources
        synchronized (account){
            //Judge whether there is money
            if (account.money-drawingMoney<0){
                System.out.println(Thread.currentThread().getName()+"Insufficient balance found!");
                return;
            }
            //Simulation delay can reduce the occurrence of method problems
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //Card balance = balance - get money
            account.money=account.money-drawingMoney;
            //The money in your hand
            nowMoney=nowMoney+drawingMoney;
            System.out.println(account.name+"Card balance:"+account.money);
            //nowMoney+Thread.currentThread().getName() == this.getName()
            System.out.println(this.getName()+"Money in hand:"+nowMoney);
        }
    }
}
---------------result---------------
Balance in wedding gift card: 5000
 Money in hand: Xiaoming 5000
 Girlfriend found insufficient balance!

After modification of case 3:

import java.util.ArrayList;
//Thread is not a very safe collection
//If sleep is removed, the main thread will output before other threads finish executing
//You can judge later and end the main thread after other threads are finished
public class UnsafeList {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                synchronized (list){
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}
---------------result---------------
10000

Expansion:

import java.util.concurrent.CopyOnWriteArrayList;
//Test the collection of JUC security types
public class TestJUC {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}
---------------result---------------
10000

8. Deadlock

Multiple threads occupy some shared resources and wait for the resources occupied by other threads to run
This causes two or more threads to stop executing while waiting for each other to release resources A synchronization block
When you have "locks of more than two objects" at the same time, the problem of "deadlock" may occur

Deadlock cases:

//Deadlock: multiple threads hold each other's required resources, and then form a deadlock
public class DeadLock {
    public static void main(String[] args) {
        Makeup g1 = new Makeup(0, "Xiao Hong");
        Makeup g2 = new Makeup(1, "Blue ");
        g1.start();
        g2.start();
    }
}

class Dior{
}

class Mirror{
}

class Makeup extends Thread{
    //There is only one resource needed. Use static to ensure that there is only one
    static Dior dior= new Dior();
    static Mirror mirror = new Mirror();
    int choice;//choice
    String girlName;//User

    Makeup(int choice,String girlName){
        this.choice=choice;
        this.girlName=girlName;
    }

    @Override
    public void run() {
        //Make up
        try {
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //Make up, hold each other's locks, and need to get each other's resources
    private void makeup() throws InterruptedException {
        if (choice==0){
            synchronized (dior){//Get lipstick lock
                System.out.println(this.girlName+"Get lipstick lock");
                Thread.sleep(1000);
                //Want to get it in a second, mirror
                synchronized (mirror){
                    System.out.println(this.girlName+"Get the lock of the mirror");
                }
            }
        }else {
            synchronized (mirror){//Get lipstick lock
                System.out.println(this.girlName+"Get the lock of the mirror");
                Thread.sleep(2000);
                //Want to get lipstick in a second
                synchronized (dior){
                    System.out.println(this.girlName+"Get lipstick lock");
                }
            }
        }
    }
}
---------------result---------------
Little red gets the lock of lipstick
 Xiaolan gets the lock of the mirror

It never ends

9. Deadlock avoidance method

Four necessary conditions for deadlock generation

  1. Mutually exclusive condition: a resource can only be used by one process at a time.
  2. Request and hold condition: when a process is blocked by requesting resources, it will hold on to the obtained resources.
  3. Conditions of non deprivation: the resources obtained by the process cannot be forcibly deprived before they are used up.
  4. Circular waiting condition: a circular waiting resource relationship is formed between several processes.

The four necessary conditions for deadlock are listed above. We can avoid deadlock as long as we try to break any one or more of them

Case modification:

public class DeadLock {
    public static void main(String[] args) {
        Makeup g1 = new Makeup(0, "Xiao Hong");
        Makeup g2 = new Makeup(1, "Blue ");
        g1.start();
        g2.start();
    }
}

class Dior{
}

class Mirror{
}

class Makeup extends Thread{
    //There is only one resource needed. Use static to ensure that there is only one
    static Dior dior= new Dior();
    static Mirror mirror = new Mirror();
    int choice;//choice
    String girlName;//User

    Makeup(int choice,String girlName){
        this.choice=choice;
        this.girlName=girlName;
    }

    @Override
    public void run() {
        //Make up
        try {
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //Make up, hold each other's locks, and need to get each other's resources
    private void makeup() throws InterruptedException {
        if (choice==0){
            synchronized (dior){//Get lipstick lock
                System.out.println(this.girlName+"Get lipstick lock");
                Thread.sleep(1000);
            }
            //Want to get it in a second, mirror
            synchronized (mirror){
                System.out.println(this.girlName+"Get the lock of the mirror");
            }
        }else {
            synchronized (mirror){//Get lipstick lock
                System.out.println(this.girlName+"Get the lock of the mirror");
                Thread.sleep(2000);
            }
            //Want to get lipstick in a second
            synchronized (dior){
                System.out.println(this.girlName+"Get lipstick lock");
            }
        }
    }
}
---------------result---------------
Little red gets the lock of lipstick
 Xiaolan gets the lock of the mirror
 Xiaolan gets the lock of lipstick
 Xiao Hong gets the lock of the mirror

10. Lock

Starting from JDK5, Java provides a more powerful thread synchronization mechanism -- synchronization is achieved by explicitly defining synchronization Lock objects. Synchronous locks use Lock objects as
java.util.concurrent.locks.Lock interface is a tool that controls multiple threads to access shared resources. Lock provides exclusive access to shared resources. Only one thread can lock the lock object at a time. Threads should obtain the lock object before accessing shared resources
ReentrantLock (reentrant Lock) class implements Lock. It has the same concurrency and memory semantics as synchronized. ReentrantLock is commonly used in thread safety control, which can explicitly add and release locks.


example:

import java.util.concurrent.locks.ReentrantLock;
//Test lock lock
public class TestLock {
    public static void main(String[] args) {
        TestLock2 testLock2 = new TestLock2();
        new Thread(testLock2,"Xiao Ming").start();
        new Thread(testLock2,"Xiao Hong").start();
        new Thread(testLock2,"I").start();
    }

}
class TestLock2 implements Runnable{
    int ticketNums=10;
    //Define lock lock
    private final ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            try {
                lock.lock();//Lock
                if (ticketNums>0){
                    System.out.println(Thread.currentThread().getName()+"Got it:"+ticketNums--);
                }else {
                    break;
                }
            }finally {
                lock.unlock();//Unlock
            }
        }
    }
}
---------------result---------------
I got it:10
 Xiao Ming got it:9
 Xiao Hong got it:8
 I got it:7
 Xiao Ming got it:6
 Xiao Hong got it:5
 Xiao Hong got it:4
 I got it:3
 Xiao Ming got it:2
 Xiao Hong got it:1

11. Comparison between synchronized and Lock

Lock is an explicit lock (manually open and close the lock, don't forget to close the lock). synchronized is an implicit lock, which is automatically released out of the scope

Lock only has code block lock, and synchronized has code block lock and method lock
Using Lock lock, the JVM will spend less time scheduling threads and perform better. And it has better scalability (providing more subclasses)

Priority order

  • Lock > synchronization code block (it has entered the method body and allocated corresponding resources) > synchronization method (on the side)
    (outside the legal body)

Topics: Java JavaSE