Java -- a simple understanding of multithreading

Posted by zapa on Sun, 13 Feb 2022 04:32:52 +0100

preface

Ten thousand words briefly summarize the multithreading in the process of Java learning. If there are deficiencies, please correct them. If you think they are good, you can also connect them three times

Thread class

  • Inherit Thread class

    • Declare a class as a subclass of a Thread. The subclass overrides the method Thread of the run class, and then allocate and start the instance of the subclass
    • Custom Thread class inherits Thread class
    • Rewrite the run () method and write the thread execution body
    • Create a thread object and call the start () method to start the thread
  • Thread creation method 1: inherit the thread class, rewrite the run () method, and call start to start the thread

  • Note: thread startup is not necessarily executed immediately, but is scheduled by CPU

  • summary

    • The subclass inherits the Thread class and has the ability of multithreading
    • Start thread: subclass object start()
    • Not recommended to avoid the limitation of OOP single inheritance
public class TestThread1 extends Thread{

    public void run(){
        
        //run method thread body
        for(int i = 0;i < 200; i++){
            System.out.println("I'm looking at the code---"+i);
        }
    }

    public static void main(String[] args) {
        //main thread

        //Create a thread object
        TestThread1 testThread1 = new TestThread1();

        //The thread start() method is called
        testThread1.start();

        for(int i = 0;i < 1000;i++){
            System.out.println("I am reading a book---"+i);
        }
    }
}
Picture download
  • Realize multi-threaded synchronous downloading of pictures
public class TestThread extends Thread{
    
    private String url;//Network picture address
    private String name;//Saved file name
    
    public TestThread(String url,String name){
        this.url = url;
        this.name = name;
    }
    
    //The execution body of the image download thread
    public void run(){
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("Downloaded the file named:"+name);
    }

    public static void main(String[] args) {
        TestThread t1 = new TestThread("","1.jpg");
        TestThread t2 = new TestThread("","2.jpg");
        TestThread t3 = new TestThread("","3.jpg");

        t1.start();
        t2.start();
        t3.start();
    }
}

//Downloader
class WebDownloader{
    //Download method
    public void downloader(String url,String name){
        try {     
            FileUtils.copyURLToFile((new URL(url)), new File(name));
        }catch (IOException e){          
            e.printStackTrace();
            System.out.println("IO Abnormal, Downloader There is a problem with the method“);
        }
    }
}

Runnable interface

  • Implement the Runable interface: declare the implementation class Runnable interface. That class then implements the run method. You can then assign an instance of the class, pass it as a parameter when creating the Thread, and start it.

  • Create thread mode 2:

    • Implement the runable interface
    • When rewriting the run method, the execution thread object needs to be thrown into the implementation class of the runnable interface
    • Call start()
  • Thread creation mode 2: implement the runnable interface, rewrite the run () method, and throw the execution thread into the thread object

  • summary

    • The implementation interface Runable has multithreading capability

    • Start Thread: pass in the target object + Thread object start()

    • Recommended: it avoids the limitation of single inheritance, is flexible and convenient, and is convenient for the same object to be used by multiple threads

public class TestThread1 implements Runnable{

    public void run(){
        //run method thread body
        for(int i = 0;i < 200; i++){
            System.out.println("I'm looking at the code---"+i);
        }
    }

    public static void main(String[] args) {
        //Create the implementation class object of runnable interface
        TestThread1 testThread1 = new TestThread1();

        //Create a thread object and start our thread through the thread object
        new Thread(testThread1).start();

        for(int i = 0;i < 1000;i++){
            System.out.println("I am reading a book---"+i);
        }
    }
}
Picture download
public class TestThread implements Runnable{
    
    private String url;//Network picture address
    private String name;//Saved file name
    
    public TestThread(String url,String name){
        this.url = url;
        this.name = name;
    }
    
    //The execution body of the image download thread
    public void run(){
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("Downloaded the file named:"+name);
    }

    public static void main(String[] args) {
        TestThread t1 = new TestThread("","1.jpg");
        TestThread t2 = new TestThread("","2.jpg");
        TestThread t3 = new TestThread("","3.jpg");
        
        new Thread(t1).start();
        new Thread(t2).start();
        new Thread(t3).start();
    }
}

//Downloader
class WebDownloader{
    //Download method
    public void downloader(String url,String name){
        try {     
            FileUtils.copyURLToFile((new URL(url)), new File(name));
        }catch (IOException e){          
            e.printStackTrace();
            System.out.println("IO Abnormal, Downloader There is a problem with the method“);
        }
    }
}
Tortoise and rabbit race
//Simulated tortoise rabbit race
public class Race implements Runnable {

    //winner
    private static String winner;

    @Override
    public void run(){

        for (int i = 0; i <= 100; i++) {
            //Simulated rabbit rest
            if (Thread.currentThread().getName().equals("rabbit") && i % 10 == 0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //Judge whether the game is over
            boolean flag = gameover(i);
            //If the game is over, stop the program
            if (flag) {
                break;
            }
            System.out.println(Thread.currentThread().getName() + "-->Run away" + i + "step");
        }
    }

    //Judge whether to complete the game
    private boolean gameover(int steps) {
        //Judge whether there is a winner
        if (winner != null) {//If winner is not null, there is a winner
            return true;
        } else {
            if (steps >= 100) {
                winner = Thread.currentThread().getName();
                System.out.println("Winner is" + winner);
                return true;
            }

        }
        return false;

    }

    public static void main(String[] args) {
        Race race = new Race();
        new Thread(race, "rabbit").start();
        new Thread(race, "tortoise").start();
    }
}

Callable interface

  • Thread creation mode 3
    • Implement the callable interface
  • Benefits of callable
    1. You can set the return value
    2. Exceptions can be thrown
  • summary
    • To implement the Callable interface, the return value type is required
    • When overriding the call method, you need to throw an exception
    • Create target object
    • Create execution service: executorservice ser = executors newFixedThreadPool(3)
    • Submit execution: futuresult1 = Ser submit(t1)
    • Get result: Boolean R1 = result1 get()
    • Shut down the service: Ser shutdownNow()
Picture download
public class TestCallable implements Callable<Boolean> {
    private String url;  //Network picture address
    private String name; //Saved file name

    //Constructor -- implementation call
    public TestCallable(String url, String name) {
        this.url = url;
        this.name = name;

    }

    //Download the execution body of the picture
    @Override
    public Boolean call() {
        WebDownloader webDownloader = new WebDownloader();
        //Incoming method
        webDownloader.downloader(url, name);
        System.out.println("The downloaded file name is" + name);
        return true;
    }

    public static void main(String[] args) throws Exception {
        TestCallable t1 = new TestCallable("http://b-ssl.duitang.com/uploads/item/201704/21/20170421083329_3cxt8.png", "1.png");
        TestCallable t2 = new TestCallable("https://i02piccdn.sogoucdn.com/7e1dad42a62db2df", "2.png");
        TestCallable t3 = new TestCallable("https://i01piccdn.sogoucdn.com/f13b319fd77655ec", "3.png");

        //Create execution service:
        ExecutorService ser = Executors.newFixedThreadPool(3);
        //Submit for execution:
        Future<Boolean> r1 = ser.submit(t1);
        Future<Boolean> r2 = ser.submit(t2);
        Future<Boolean> r3 = ser.submit(t3);
        //Get results:
        boolean rs1 = r1.get();
        boolean rs2 = r2.get();
        boolean rs3 = r3.get();

        //Shut down service:
        ser.shutdownNow();
    }
}

//Downloader
class WebDownloader {
    //Download - Method
    public void downloader(String url, String name) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO Abnormal, down There is a problem with your method!");
        }
    }

}

Static proxy mode

  • concept

    • Both real objects and proxy objects need to implement an interface
    • The proxy object should represent the real role
  • benefit

    • Proxy objects can do many things that real objects cannot do
    • Real objects focus on doing their own things
public class StaticProxy {
    public static void main(String[] args) {

        You you=new You();
        WeddingCompany weddingCompany=new WeddingCompany(you);
        //Equivalent to new WeedingCompany (new you())
        weddingCompany.HappyMarry();
    }
}

//Functional interface
interface Marry{
    void HappyMarry();
}

//Implement Mary's interface
//Real role
class You implements Marry{
    @Override
    public void HappyMarry() {
        System.out.println("Are you getting married?,Looks super happy");
    }
}

//Implement Mary's interface
//Acting role - wedding company
class  WeddingCompany implements Marry{

    //Proxy real object
    private Marry target;

    //Construction method
    public WeddingCompany(Marry target){
        this.target=target;
    }

    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();//This is the real object
        after();
    }
    private void before(){
        System.out.println("Before marriage, set up the scene");

    }

    private void after(){
        System.out.println("After marriage, the final payment");

    }
}

Lamda expression

  • λ The eleventh letter in the Greek alphabet. Its English name is Lambda
  • Avoid too many anonymous internal definitions
  • Its essence belongs to the concept of functional programming
    • (params) - > exosession [expression]
    • (params) - > statement [expression]
    • (params) - > [expression]
    • a->System.out.println("I Like lamdbda2");
  • Definition of Functional Interface
  • Any interface that contains only one abstract method is a functional interface
public interface Runnable{
	public abstract void run();
}
  • For functional interfaces, we can create the interface object through lamdba expression
  • Example 1
//Derivation of Lambda expression
public class TestLambda01 {
 //Add static (3. Static required)
   static  class Like2 implements ILike
    {
        @Override
        public void lambda() {
            System.out.println("I Like lamdbda2");

        }
    }

    //After defining the interface and implementation class (implementation interface), write the main method
    public static void main(String[] args) {
        //Functional interface name + user defined variable = new + implementation class (implementation interface) variable Like
        ILike like=new Like();
        like.lambda();

        //Static inner class
        //Custom variable name = new + implementation class (implementation interface) variable Like2
        like=new Like2();
        like.lambda();

        //4. Local internal class
        class Like3 implements ILike
        {
            @Override
            public void lambda() {
                System.out.println("I Like lamdbda3");

            }
        }
        like=new Like3();
        like.lambda();

        //5. Anonymous inner class. There is no class name. You must use the interface or parent class
        like = new ILike() {
            @Override
            public void lambda() {
                System.out.println("I Like lamdbda4");
            }
        };
        like.lambda();

        //6. Simplify connection with lambda
        like=()-> {
            System.out.println("I Like lamdbda5");
        };
        like.lambda();
    }
}

//1. Define a functional interface
interface ILike{
    void lambda();

}

//2. Implementation class (implementation interface)
//implements
class Like implements ILike
{
    @Override
    public void lambda() {
        System.out.println("I Like lamdbda1");

    }
}
  • Example 2
public class TestLambda02 {
    public static void main(String[] args) {
        ILove love=null;

      //1.lambda simplification
       /* ILove love=(int a)->{
                System.out.println("I Love You-->"+a);
        };

      //Simplify 1 Parameter type
        love=(a)->{
            System.out.println("I Love You-->"+a);
        };*/

        //Simplification 2 Simplified parentheses
        love=(a,b)->{
            System.out.println("I Love You-->"+a+"-->"+b);
        };
         love.love(521,520);

        //Simplify 3 Remove curly braces
        love=(a,b)-> System.out.println("I Love You-->"+a+"-->"+b);
        love.love(521,520);
    }
}

//Functional interface
interface ILove{
    void love(int a,int b);
}
  • summary
    1. lambda expressions can only be reduced to one line if they have only one line of code
    2. If there are multiple lines, wrap them in code blocks (i.e. curly braces)
    3. The premise is that the interface must be functional (only one method)
    4. Parameter types can also be removed from multiple parameters. If you want to remove them, you must remove them all and add parentheses (a,b)

Thread state

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 yieldPauses 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
Thread stop
  • It is recommended that the thread stop normally - > utilization times, and dead loop is not recommended
  • It is recommended to use flag bit - > set a flag
  • Do not use outdated methods such as stop or destroy, or methods that are 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 public method to stop the thread and convert the flag bit
    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){
                //Call the stop method to stop the thread
                testStop.stop();
                System.out.println("Thread has reached 900, stop");
            }
        }
    }
}
Thread sleep
  • sleep (time) specifies the number of milliseconds that the current thread is blocked (1000ms=1s)
  • Exception InterruptedException in sleep
  • When the sleep time arrives, 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
  • Analog network delay: the occurrence of amplification problems
public class TestSleep implements  Runnable{
    //Number of votes
    private int ticketNums = 10;
    @Override
    public void run() {
        while(true)
        {
            if(ticketNums<=0) {
                break;
            }
            //Analog delay
            
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->Got the second"+ticketNums--+"ticket");
        }
    }

    public static void main(String[] args) {
        TestSleep ticket=new TestSleep();

        //Random output
        new Thread(ticket,"Xiao Ming").start();
        new Thread(ticket,"teacher").start();
        new Thread(ticket,"Scalpers").start();
    }
}
  • Realize the countdown and obtain the system time
//Analog countdown
public class TestSleep02 {
    public static void main(String[] args) {
        //Analog countdown
        //tenDown();

        //Print current system time
       Date startTime = new Date(System.currentTimeMillis());//Get the current time of the system
        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
               startTime = new Date(System.currentTimeMillis());//Update current system time
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
  
    public static void tenDown(){
        int num=10;
        while(true){

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(num--);
            if(num<=0)
            {
                break;
            }

        }
    }
}
Thread yield
  • Comity thread: pause the currently executing thread without blocking it
  • Change the thread from running state to ready state
  • Let the CPU readjust, 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();

        //Start thread
        new Thread(myYield,"a").start();
        new Thread(myYield,"b").start();
    }
}

//A thread class is required
class MyYield implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"Thread start execution");
        Thread.yield();//Thread comity
        System.out.println(Thread.currentThread().getName()+"Thread stop execution");

    }
}
Thread join
  • Join merge threads. After this thread is successfully executed, execute other threads. Other threads are blocked (you can imagine jumping in line)
//Test Join
public class TestJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("vip The VIP is coming. Please make way!"+i);
        }
    }

    public static void main(String[] args) {
        //Start thread
        TestJoin testJoin=new TestJoin();
        Thread thread=new Thread(testJoin);
        thread.start();
        //Main thread
        for (int i = 0; i < 1000; i++) {
            if(i==200){
                try {
                    thread.join();//Jump in line
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("main"+i);
        }    
    }
}
Thread state
  • A thread can be in one of the following states
    • NEW
      Threads that have not been started are in this state.
    • RUNNABLE
      The thread executing in the Java 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) {
        Thread thread=new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("123123");
        });

        //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

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            state=  thread.getState();//Update thread status
            System.out.println(state);//Output status
        }      
    }
}
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 (performance inversion)
daemon thread
  • Threads are divided into user threads and daemon threads
    • setDaemon has only two values true/false
    • The default value is false, which means user threads. Normal threads are user 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
  • Example: record operation logs in the background, monitor memory, garbage collection, etc
//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);

        //Start daemon thread
        thread.start();


        new Thread(you).start();//User thread start
    }
}

//Daemon thread
class  God  implements  Runnable{
    @Override
    public void run() {
        while(true)
        {
            System.out.println("Buddha bless you!");
        }

    }
}

//User thread
class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("You live happily all your life!");
        }
        System.out.println("=======goodbye world!=======");
    }
}

Thread synchronization

Thread synchronization mechanism
  • Concurrency: the same object is operated by multiple threads at the same time

  • When dealing with multithreading, when multiple threads access the same object and some threads want to modify the object, we need thread synchronization. Thread synchronization is actually a waiting mechanism. Multiple threads that need to access the object at the same time enter the waiting pool of the object to form a queue, wait for the previous thread to use it, and then use it again for the next thread

  • Conditions for thread synchronization: queue + lock

  • Defects in thread synchronization

    • Since 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 access in the method, a lock mechanism is added during access
    • When a thread obtains the exclusive lock of an object and monopolizes resources, other threads must wait and release the lock after use
    • Thread synchronization has the following problems
      • Holding a lock by one thread will cause all other threads that need the lock to hang
      • When multiple threads compete, locking and releasing locks will lead to more context switching and scheduling delays, resulting in performance problems
      • If a high priority thread waits for a low priority thread to release the lock, it will lead to priority inversion and performance problems
Three unsafe cases
  • Case 1
//Unsafe ticket purchase
//Thread unsafe, with 0 and negative output
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket station=new BuyTicket();

        new Thread( station,"Huahua 001").start();
        new Thread( station,"Huahua 002").start();
        new Thread( station,"Huahua 003").start();

    }
}

//Need a ticket purchasing method (a multi thread)
class BuyTicket implements Runnable{
    //Number of votes required
    private int ticketNums=10;
    boolean flag=true;//External stop mode
    
    @Override
    public void run() {
        while (flag){
            buy();

        }

    }
    
    //Create ticket buying method
    private  void buy(){
        //Judge whether there are tickets
        if (ticketNums<=0)
        {
            flag=false;
            return;
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Buy a ticket
        System.out.println(Thread.currentThread().getName()+"Get"+ticketNums--);
    }
}
  • Case 2
//Unsafe withdrawal
//Need two people to withdraw money from the bank -- > need an account
public class UnsafeBank {
    public static void main(String[] args) {
        //account
        Account account=new Account(100,"Marriage funds");
        Drawing you=new Drawing(account,50,"you");
        Drawing yougirlfriend=new Drawing(account,100,"yougirlfriend");
        you.start();
        yougirlfriend.start();
    }
}

//account
class Account{
    int money;//balance
    String name;//Card number
    public Account(int money, String name) {
        this.money=money;
        this.name=name;
    }
}

//bank.... Simulated withdrawal
class  Drawing extends Thread{
    Account account;//account
    int drawingMoney; //How much did you withdraw
    int nowMoney;  //Cash in hand
    public Drawing(Account account, int drawingMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
    }
    @Override    //Withdraw money
    public void run() {
        if(account.money-drawingMoney<0){//Judge whether the account has balance
            System.out.println(Thread.currentThread().getName()+"Sorry, your credit is running low!");
            return;
        }
        try {
            Thread.sleep(1000); //The occurrence of sleep amplification problem
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        account.money= account.money-drawingMoney;//Card balance = balance - the money you withdraw
        nowMoney=nowMoney+drawingMoney;  //The money in your hand
        System.out.println(Thread.currentThread().getName()+"Money in hand:"+nowMoney);
        System.out.println(account.name+"The balance is:"+account.money);
        //Here is this Getname () is equivalent to thread currentThread(). getName()
    }
}
  • Case 3
//Thread unsafe collection
public class UnsafeList {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(list.size());

    }
}
Synchronization method and synchronization block
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 uses: synchronized method and synchronized block
  • Synchronization method
public synchronizeed void method(int args){}
  • The synchronized method controls access to "objects", and 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 and release the lock until the method returns. The blocked thread can obtain the lock and continue to execute
    • Defect: declaring a large method synchronized will affect efficiency
Synchronization block
  • synchronized(Obj){}

  • Obj calls it a synchronization monitor

    • Obj can be any object, but it is recommended to use shared resources 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
  • Synchronization monitor execution process

    • The first thread accesses, locks the synchronization monitor, and executes the code in it

    • The second thread accesses and finds that the synchronization monitor is locked and cannot be accessed

    • After the first thread is accessed, unlock the synchronization monitor

    • The second thread accesses, finds that the synchronization monitor has no lock, and then locks and accesses

  • Using synchronization to solve three unsafe cases

  • Case 1

//Unsafe ticket purchase
//Thread unsafe, with 0 and negative output
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket station=new BuyTicket();

        new Thread( station,"Huahua 001").start();
        new Thread( station,"Huahua 002").start();
        new Thread( station,"Huahua 003").start();

    }
}

//Need a ticket purchasing method (a multi thread)
class BuyTicket implements Runnable{
    //Number of votes required
    private int ticketNums=10;
    boolean flag=true;//External stop mode

    @Override
    public void run() {
        while (flag){
            buy();
        }
    }

    //Create ticket buying method
    //The synchronized synchronization method locks this (BuyTicket)
    private synchronized  void buy(){
        //Judge whether there are tickets
        if (ticketNums<=0)
        {
            flag=false;
            return;
        }

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //Buy a ticket
        System.out.println(Thread.currentThread().getName()+"Get"+ticketNums--);
    }
}
  • Case 2
//Unsafe withdrawal
//Need two people to withdraw money from the bank -- > need an account
public class UnsafeBank {
    public static void main(String[] args) {
        //account
        Account account=new Account(100,"Marriage funds");
        Drawing you=new Drawing(account,50,"you");
        Drawing yougirlfriend=new Drawing(account,100,"yougirlfriend");
        you.start();
        yougirlfriend.start();
    }
}

//account
class Account{
    int money;//balance
    String name;//Card number
    public Account(int money, String name) {
        this.money=money;
        this.name=name;
    }
}

//bank.... Simulated withdrawal
class  Drawing extends Thread{
    Account account;//account
    int drawingMoney; //How much did you withdraw
    int nowMoney;  //Cash in hand
    public Drawing(Account account, int drawingMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
    }
    
    @Override    
    //Withdraw money
    // synchronized the default lock is this
    //The object of the lock is the amount of change, that is, the amount that needs to be added, deleted and modified
    public void run() {
        synchronized(account){
            if(account.money-drawingMoney<0){//Judge whether the account has balance
                System.out.println(Thread.currentThread().getName()+"Unable to withdraw money, insufficient balance!");
                return;
            }
            try {
                Thread.sleep(1000); //The occurrence of sleep amplification problem
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.money= account.money-drawingMoney;//Card balance = balance - the money you withdraw
            nowMoney=nowMoney+drawingMoney;  //The money in your hand
            System.out.println(Thread.currentThread().getName()+"Money in hand:"+nowMoney);
            System.out.println(account.name+"The balance is:"+account.money);
            //Here is this Getname () is equivalent to thread currentThread(). getName()

        }
    }
}
  • Case 3
//Thread unsafe collection
public class UnsafeList {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                synchronized (list){
                    list.add(Thread.currentThread().getName());
                }

            }).start();
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(list.size());

    }
}
CopyOnWriteArrayList
//Test the collection of JUC security types
public class TestJUC {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}
deadlock
  • Multiple threads occupy some shared resources and wait for the resources occupied by other threads to run. As a result, two or more threads are waiting for each other to release resources and stop execution. When a synchronization block has (locks of more than two objects) at the same time, the problem of (deadlock) may occur
package thread;
//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,"Grey Gu Liang");
        Makeup g2=new Makeup(1,"Bai Guliang");
        g1.start();
        g2.start();
    }
}

//Lipstick
class Lipstick{
}

//mirror
class Mirror{
}

//Make up
class  Makeup extends Thread{
      //There is only one resource needed. Use static to ensure that there is only one
    static Lipstick lipstic=new Lipstick();
    static Mirror mirror=new Mirror();

    int choice; //choice
    String girlname;//People who use cosmetics
    //Using constructors
    Makeup(int choice,String girlname){
        this.choice=choice;
        this.girlname=girlname;
    }

    //To inherit the Thread type, you need to override the run method
    @Override
    public void run() {
        try {
            makeup();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //Make up
    }
    //Make up, hold each other's locks, and need to get each other's resources
    private void makeup(){
        if(choice==0)
        {
            synchronized (lipstic){//Get lipstick lock
                System.out.println(this.girlname+"Get lipstick lock");
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            //The way to solve the deadlock is to take the synchronized (mirror) below out of the if statement
            synchronized (mirror){//I want to get the mirror in a second
                System.out.println(this.girlname+"Get the lock of the mirror");
            }

        }else{
            synchronized (mirror) {//Get the lock of the mirror
                System.out.println(this.girlname + "Get the lock of the mirror");
                try {
                    Thread.sleep(2000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
             //The way to solve the deadlock is to take the synchronized (lipstic) below out of the else statement
            synchronized (lipstic) {//Want to get lipstick in a second
                System.out.println(this.girlname + "Get lipstick lock");
            }
        }

    }
}
  • Conditions for deadlock generation
    • Mutex condition: a resource can only be used by one process at a time
    • Request and hold condition: when a process is blocked by requesting resources, it will hold on to the obtained resources
    • Conditions of non deprivation: the resources obtained by the process cannot be forcibly deprived before they are used up
    • Cyclic waiting condition: a cyclic 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
LocK lock
  • From jdk5 Since 0, Java has provided a more powerful thread synchronization mechanism - synchronization is achieved by explicitly defining the synchronization Lock object, which uses the Lock object as the
  • 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 class implements Lock. It has the same concurrency and memory semantics as synchronized. ReentrantLock is commonly used in thread safety control. It can explicitly add and release locks
  • format
//grammar
class  A{
    private  final  ReentrantLock lock=new ReentrantLock();
    public  void  mainone(){
        try{
            lock.lock();
            //Thread safe code
        }finally {
            lock.unlock();
            //If the finally synchronization code has an exception, write unlock () to the statement block
        }
    }
}
  • case
//Test Lock
public class TestLock {
    public static void main(String[] args) {
        TestLock2 testLock2=new TestLock2();

        new Thread(testLock2).start();
        new Thread(testLock2).start();
        new Thread(testLock2).start();
	}
}

class TestLock2 implements  Runnable{
   	int ticketNums=10;

   //Define Lock lock (reentrant Lock)
    private final   ReentrantLock lock =new ReentrantLock();

    @Override
    public void run() {
       while(true)
       {
           try{
           	   lock.lock();//Lock
               if(ticketNums>0){
                   try {
                       Thread.sleep(1000);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   System.out.println(ticketNums--);
               }else{
                   break;
               }
       		}finally{
               //Unlock
               lock.unlock();
       		}
       }
    }
}
  • synchronized vs Lock
    • Lock is an explicit lock (manually open and close the lock, don't forget to close the lock), and 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, with better performance and better scalability (providing more subclasses)
    • Priority: Lock > sync code block > sync method

Thread collaboration

Thread communication
Method nameeffect
wait()Different from other threads, sleep means that the lock will be released all the time
wait(long timeout)Specifies the number of milliseconds to wait
notify()Wake up a waiting thread
notifyAll()Wake up all threads calling the wait() method on the same object, and the threads with high priority are scheduled first
  • All methods of Object class can only be used in synchronization methods or synchronization code blocks, otherwise different iiiegamonitorstateexception will be thrown
producer consumer problem
  • Pipe program method
//Producer consumer product buffer
public class TestPC {
    public static void main(String[] args) {
        
            SynContainer container=new SynContainer();
            new Productor(container).start();
            new Consumer(container).start();
    }
}

//producer
class Productor extends Thread{
    SynContainer container;
    public Productor(SynContainer container){
       this.container=container;
    }
    //Production method required
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("Produced"+i+"Chicken");
            container.push(new Chicken(i));
        }
    }
}

//consumer
class Consumer extends Thread{
    SynContainer container;
    public Consumer(SynContainer container){
        this.container=container;
    }

    //consumption
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("Consumption--->"+container.pop().id+"Chicken");
        }
    }
}

//product
class  Chicken{
    int id;//Product number is required
    //Construction method alt+insert
    public Chicken(int id) {
        this.id = id;
    }
}

//buffer
class SynContainer {
    //A container size is required
    Chicken[] chickens = new Chicken[10]; 
    int count = 0;//Container counter
    //Producers put in products (synchronized to achieve synchronization)
    public synchronized void push(Chicken chicken) {
        //If the container is full, it needs to wait for consumers to consume
        if (count == chickens.length) {
            //This is the need to inform consumers, production waiting
         try{
              this.wait();
             }catch (InterruptedException e){
              e.printStackTrace();
               }
        }
        //If it is not full, we need to put in the product
        chickens[count] = chicken;
        count++;
        //Consumers can be informed of consumption
        this.notifyAll();
    }


    //Consumer products
    public synchronized Chicken pop(){
    //Judge whether it can be consumed
        if (count == 0) {
            //Wait for producers to produce and consumers to wait
           try{
               this.wait();
           }catch (InterruptedException e){
               e.printStackTrace();
           }
        }
        //If you can consume
        count--;
        Chicken chicken = chickens[count];
        //After eating, inform the producer to produce
        this.notifyAll();
        return chicken;
    }
}
  • Signal lamp method
public class TestPC2 {
    public static void main(String[] args) {
        TV tv=new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}

//Producer -- > actor
class Player extends Thread{
    TV tv;
    public Player(TV tv){  //Construction method
        this.tv=tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if(i%2==0){
                this.tv.play("Happy camp playing");
            }else{
                this.tv.play("Jitter: tiktok: record the good life");
            } 
        }
    }
}


//Consumer -- > audience
class Watcher extends Thread{
    TV tv;
    public Watcher(TV tv){  //Construction method
        this.tv=tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            tv.watch();
        }
    }
}

//Products -- > Programs
class TV {
    //The actors performed and the audience waited
    //Audience watching, actors waiting for False
    String  voice;//A performance
    boolean flag=true;//Set the flag bit to judge whether the actor performs

    //perform
    public synchronized  void  play(String voice){
        if(!flag){ //If the audience is watching, the actor needs to wait for this wait();
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("The actors performed:"+voice);
        //Inform the audience to watch
        this.notifyAll();//Notification (wake up)
        this.voice=voice;
        this.flag=!this.flag;

    }

    //watch
    public  synchronized  void watch(){
        if(flag){  //If the actor is performing. The audience needs to wait for this wait();
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("The audience watched:"+voice);

        //Inform the actors of the performance after the audience has watched
        this.notifyAll();
        this.flag=!this.flag;
    }
}
Thread pool
  • Background: resources that are often created and destroyed and used heavily, such as threads in concurrency, have a great impact on performance

  • Idea: create many threads in advance, put them into the thread pool, get them directly when using them, and put them back into the pool after using them

  • It can avoid frequent creation and destruction and realize reuse. Similar to public transport in life

  • benefit

    • Improved response speed (reduced time to create new threads)

    • Reduce resource consumption (reuse threads in the thread pool and do not need to be created every time)

    • Easy thread management (...)

      • corePoolSize: the size of the core pool
      • maximumPoolSize: maximum number of threads
      • keepAliveTime: when a thread has no task, how long does it last at most and then it will terminate
  • a key

    • JDK5. Thread pool related API s: ExecutorService and Executors have been provided since 0

    • ExecutorService: the real thread pool interface. Common subclass ThreadPoolExcutor

    • Runnable: no command, runnable: no command to execute

    • Future submit(Callable ask): when a task is executed and there is a return value, it is generally executed again

    • void shutdown(): closes the connection pool

    • Executors: tool class and factory class of thread pool, which are used to create and return thread pools of different types

//Test thread pool
public class TestPool {
    public static void main(String[] args) {
        //1. Create service and thread pool
        //The newFixedThreadPool parameter is the size of the thread pool
        ExecutorService service= Executors.newFixedThreadPool(10);

        //implement
        service.execute(new MyTread());
        service.execute(new MyTread());
        service.execute(new MyTread());
        service.execute(new MyTread());

        //2. Close the connection pool
        service.shutdown();

    }
}

class MyTread implements  Runnable{
    @Override
    public void run() {
            System.out.println(Thread.currentThread().getName());

    }
}

Topics: Java Back-end