Java based multithreading

Posted by Texan on Wed, 10 Nov 2021 18:26:33 +0100

1. Thread introduction

1.1 multithreading

Multitasking: playing mobile while eating

But in essence, the brain still does only one thing at a time

1.2 program, process and thread

The program is static, and the process is the process of program execution. A process can have multiple threads, and the real execution is threads

2. Three ways to create threads

2.1 inherit Thread class

//Thread creation method 1: inherit the thread class, rewrite the run() method, and call start to start the thread
public class TestThread1 extends Thread{
    @Override
    public void run() {
        //run method thread body
        for (int i = 0; i <20 ; i++) {
            System.out.println("I'm looking at the code");

        }
    }

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

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

        //Call the start() method to start the thread
        testThread1.start();
        
        for (int i = 0; i < 2000; i++) {
            System.out.println("I'm learning multithreading");
        }

        }
    }

Summary:

  • Thread startup is not necessarily executed immediately, but is scheduled by the CPU
  • Thread creation method 1: inherit the thread class, rewrite the run() method, and call start to start the thread

2.2 example: network diagram Download

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

//Practice Thread to realize multi-threaded synchronous downloading of pictures
public class TestThread2 extends Thread{

    private String url;//Network picture address
    private String name;//Saved file name
    public TestThread2(String url ,String name){
        this.url=url;
        this.name=name;
    }

    //The execution body of the download image thread
    @Override
    public void run() {
        WebDownloader webDownloader=new WebDownloader();
        webDownloader.downloade(url,name);
        System.out.println("Downloaded a file named:"+name);
    }
    public static void main(String[] args){
        TestThread2 t1=new TestThread2("https://www.51wendang.com/doc/c4ea862180e68ca5a074899dfd85634723c2e5ec/10","2.jpg");
        t1.start();
    }
}

//Downloader
class WebDownloader{
    //Download method
    public void downloade(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO abnormal");
        }
    }
}

2.3 runnable interface

//Thread creation method 1: implement the runnable interface and rewrite the run() method. The execution thread needs to throw in the runnable interface implementation class and call the start method
public class TestThread3 implements Runnable{
    @Override
    public void run() {
        //run method thread body
        for (int i = 0; i <20 ; i++) {
            System.out.println("I'm looking at the code"+i);

        }
    }

    public static void main(String[] args) {
        //Create an implementation class object for the runnbale interface
        TestThread3 testThread3=new TestThread3();
        //Create a thread object and start our thread proxy through the thread
        Thread thread=new Thread(testThread3);
        thread.start();
        new Thread(testThread3).start();

        for (int i = 0; i < 20; i++) {
            System.out.println("I'm learning multithreading"+i);
        }

    }
}

Inherit Thread class

  • Subclass inherits Thread class and has multithreading capability
  • start thread: subclass object. start()
  • Not recommended: avoid the limitation of OOP single inheritance

Implement Runnable interface

  • The implementation interface Runnable 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

Multiple threads operate on the same object case

public class TestThread4 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();
            }
            //Gets the name of the Thread
            System.out.println(Thread.currentThread().getName()+"Got the second"+ticketNums--+"ticket");
        }
    }
    public static void main(){
        TestThread4 testThread4=new TestThread4();
        new Thread(testThread4,"Xiao Ming");
        new Thread(testThread4,"teacher");
        new Thread(testThread4,"cattle");
    }
}

2.4 tortoise 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++) {
                if (Thread.currentThread().getName().equals("rabbit") && i % 10 == 0) {
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                boolean flag=gameOver(i);
                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){
            return true;
        }{
            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();
    }
}

(3) Callable interface (understand)

package Callable;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

public class TestCallable implements Callable<Boolean> {
    private String url;//Network picture address
    private String name;//Saved file name
    public TestCallable(String url ,String name){
        this.url=url;
        this.name=name;
    }

    //The execution body of the download image thread
    @Override
    public Boolean call() {
        WebDownloader webDownloader=new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("Downloaded a file named:"+name);
        return true;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable t1=new TestCallable("https://www.51wendang.com/doc/c4ea862180e68ca5a074899dfd85634723c2e5ec/10","1.jpg");
        TestCallable t2=new TestCallable("https://www.51wendang.com/doc/c4ea862180e68ca5a074899dfd85634723c2e5ec/10","2.jpg");
        TestCallable t3=new TestCallable("https://www.51wendang.com/doc/c4ea862180e68ca5a074899dfd85634723c2e5ec/10","3.jpg");

        //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");
        }
    }
}

Callable benefits:

  • You can define the return value
  • Exceptions can be thrown

3.Thread class proxy object

Summary of static proxy mode:

  • Both real roles and proxy objects need to implement the same interface
  • The proxy object is to proxy the real role

Benefits:

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

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("123");
            }
        }).start();
        new WeddingCompany(new You()).HappyMarry();
        new WeddingCompany(new You());
        WeddingCompany weddingCompany=new WeddingCompany(new You());
        weddingCompany.HappyMarry();
    }
}
interface Marry{
    void HappyMarry();
}
//Real character, you get married
class You implements Marry{
    @Override
    public void HappyMarry() {
        System.out.println("Teacher Qin married");
    }
}
//Acting role to help you get married
class WeddingCompany implements Marry{

    private Marry target;

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


    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();
        after();

    }

    private void after() {
        System.out.println("After marriage");
    }

    private void before() {
        System.out.println("Before marriage");
    }
}

4.Lamda expression

4.1 why use lambda expressions?

  • Avoid too many anonymous inner class definitions
  • It can make your code look more concise
  • Removed a pile of meaningless code, leaving only the core logic

Definition of functional interface

  • Any interface that contains only one abstract method is a functional interface
  • For functional interfaces, you can create objects of the interface through Lambda expressions
public class lamdba {
    //3. Static internal class
   static class Like2 implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda2");
        }
    }


    public static void main(String[] args) {
        ILike like=new Like();
        like.lambda();

        like=new Like2();
        like.lambda();

        //4. Local internal class
        class Like3 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda3");
            }
        }
        like=new Like3();
        like.lambda();

        //5. Anonymous internal class. There is no class name. You must use the interface or parent class. Pay attention to the semicolon
        like=new ILike(){
            @Override
            public void lambda() {
                System.out.println("i like lambda4");
            }
        };
        like.lambda();

        //6. Simplify with Lambda
        like=()->{
            System.out.println("i like lambda5");
        };
        like.lambda();

    }
}

//1. Define a functional interface
interface ILike{
    void lambda();
}
//2. Implementation class
class Like implements ILike{

    @Override
    public void lambda() {
        System.out.println("i like lambda1");
    }
}
  • External classes are placed inside to become static internal classes, and static needs to be added
  • Static methods can only use static members
  • main is static and cannot access non static methods and variables in a class
  • Local inner classes are placed directly in methods

lambda simplification

ILove love=null;
//1.lambda simplification
 love=(int a)->{
    System.out.println("i love you-->"+a);
}
//Simplified parameter type
love=(a)->{
    System.out.println("i love you-->"+a);
}
//Simplified parentheses
love=a->{
    System.out.println("i love you-->"+a);
}
//Simplified curly braces
love=a->System.out.println("i love you-->"+a);

love.love(521);

Summary:

  • lambda expressions can be reduced to one line only if there is one line of code. If there are multiple lines, they are wrapped in code blocks
  • The premise is that the interface is functional
  • You can also remove parameter types from multiple parameters. If you want to remove them, you can remove them all,

5. Thread status

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-XOV919Ln-1636557470627)(E: \ desktop \ document \ javaweb \ multithreaded. assets\image-20211109150003879.png)]

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-PxiJTi9e-1636557470628)(E: \ desktop \ document \ javaweb \ multithreaded. assets\image-20211109150143641.png)]

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-9XFBcUJX-1636557470630)(E: \ desktop \ document \ javaweb \ multithreaded. assets\image-20211109150334204.png)]

5.1 thread stop

//Test stop
//1. It is recommended that the thread stop normally -- > utilization times, and dead loop is not recommended
//2. It is recommended to use flag bit -- > to set a 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......ing"+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 switch the flag bit and stop the thread
                testStop.stop();
                System.out.println("The thread should stop");
            }

        }
    }
}

be careful:

  • It is recommended that the thread stop normally – > utilization times, and dead loop is not recommended
  • It is recommended to use flag bit – > to set a flag bit
  • Do not use outdated methods such as stop or destroy, or methods that are not recommended by JDK

5.2 thread hibernation

//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();
            }
            //Gets the name of the Thread
            System.out.println(Thread.currentThread().getName()+"Got the second"+ticketNums--+"ticket");
        }
    }

    public static void main(String[] args) {
        TestSleep testThread4=new TestSleep();
        new Thread(testThread4,"Xiao Ming").start();
        new Thread(testThread4,"teacher").start();
        new Thread(testThread4,"cattle").start();
    }
}

import java.text.SimpleDateFormat;
import java.util.Date;

public class TestSleep2 {
    public static void main(String[] args) {
        //count down
        try {
            tenDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //Print current system time
        Date startTime=new Date(System.currentTimeMillis());//get SysTime
        while(true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
                startTime=new Date(System.currentTimeMillis());//Update current time
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    //Analog countdown
    public static void tenDown() throws InterruptedException {
        int num=10;
        while(true){
            Thread.sleep(1000);
            System.out.println(num--);
            if (num<=0){
                break;
            }
        }
    }
}

be careful:

  • sleep specifies the number of milliseconds the current thread is blocking
  • Exception InterruptedException in sleep
  • When the sleep time reaches, the thread enters the ready state
  • sleep can simulate network delay, countdown, etc
  • Each object has a lock, and sleep does not release the lock

5.3 comity

//Test comity thread
//Comity does not necessarily succeed. It depends on your mood
public class TestYied {
    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()+"Thread starts execution");
        Thread.yield();//Thread comity
        System.out.println(Thread.currentThread().getName()+"Thread stop execution");
    }
}

be careful:

  • Comity thread, which suspends the currently executing thread without blocking
  • Transition a thread from a running state to a ready state
  • Let the CPU reschedule, comity is not necessarily successful! Look at CPU mood

5.4 thread enforcement

public class TestJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("thread  vip coming"+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 < 1000; i++) {
            if (i==200){
                thread.join();//Jump in line
            }
            System.out.println("main"+i);

        }
    }
}

6. Thread state observation

public class TestSate {
    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();
                }
            }
        });
        //Observation state
        Thread.State state=thread.getState();
        System.out.println(state);
        //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 always outputs the state
            Thread.sleep(100);
            state=thread.getState();//Update thread status
            System.out.println(state);

        }
    }
}

7. Thread priority

//Test thread priority
public class TestPriority {
    public static void main(String[] args) {
        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);
        Thread t5=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();

        t5.setPriority(1);
        t5.start();

    }
}
class MyPriority implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }
}

Summary:

  • java provides a thread scheduler to monitor all threads in 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 mathematically, ranging from 1 to 10

    • Thread.MIN_PRIOITY=1;
    • Thread.MAX_PRIORITY=10;
    • Thread.NORM_PRIORITY=5;
  • Change or get priority in the following ways

    • getPriority
    • setPriority(int XXX)
  • Priority should be set 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. This depends on the CPU scheduling (performance inversion)

8. Daemon thread

//Test daemon thread
//God protects you
public class TestDamon {
    public static void main(String[] args) {
        God god=new God();
        Youe you=new Youe();
        Thread thread=new Thread(god);
        thread.setDaemon(true);//The default is false, which means that it is a user thread. Normal threads are user threads
        thread.start();//God daemon thread start
        new Thread(you).start();
    }
}
//lord
class God implements Runnable{

    @Override
    public void run() {
        while (true){
            System.out.println("God bless you");
        }
    }
}
//you
class Youe implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("You live happily all your life");

        }
    }
}

be careful:

  • 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
  • Such as: recording operation logs in the background, monitoring memory, garbage collection and so on

9. Thread synchronization

Multiple threads operate on the same resource

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

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 that need to access this object at the same time enter the waiting pool of this object to form a queue, wait for the previous thread to be used, and then use the next thread

Forming condition: queue + lock

Locking mechanism: synchronized

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 access 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.

The following problems exist:

  • Holding a lock by one thread will cause all other threads that need the lock to hang
  • In multi-threaded competition, 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.

10. Three cases of insecurity

//Unsafe ticket buying
//Thread unsafe
public class UnsafeBuy {
    public static void main(String[] args) {
        BuyTicket station=new BuyTicket();

        new Thread(station,"Xiao Ming").start();
        new Thread(station,"I").start();
        new Thread(station,"Qin Dynasty").start();
    }

}

class BuyTicket implements Runnable{
    //ticket
    private int ticketNums=10;
    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(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Buy a ticket
        System.out.println(Thread.currentThread().getName()+"Get"+ticketNums--);
    }
}

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-HPlOwnyi-1636557470632)(E: \ desktop \ document \ javaweb \ multithreaded. assets\image-20211110184917492.png)]

Someone gets 0, - 1. The thread is not safe

//Unsafe withdrawal
//Two people go to the bank to withdraw money and open an account
public class UnsafeBank {
    public static void main(String[] args) {
        //account
        Account account=new Account(100,"Marriage fund");
        Drawing you=new Drawing(account,50,"you");
        Drawing girlFrend=new Drawing(account,100,"girlFrend");
        you.start();
        girlFrend.start();

    }

}

//account
class Account{
    int money;//balance
    String name;//Card name

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

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

    public Drawing(Account account,int drawingMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
    }
    //Withdraw money

    @Override
    public void run() {
        //Judge whether there is money
        if(account.money-drawingMoney<0){
            System.out.println(Thread.currentThread().getName()+"There's not enough money to withdraw");
            return;
        }
        //sleep can amplify the occurrence of problems
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Card balance = balance - you get money
        account.money=account.money-drawingMoney;
        //The money in your hand
        nowMoney =nowMoney+drawingMoney;

        System.out.println(account.name+"The balance is:"+account.money);
        //Thread.currentThread().getName()=this.getName()
        System.out.println(this.getName()+"Money in hand:"+nowMoney);
    }
}

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (IMG siyroxzr-1636557470634) (E: \ desktop \ document \ javaweb \ multithreaded. assets\image-20211110185053642.png)]

import java.util.ArrayList;
import java.util.List;

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

11. 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: the synchronized method and the synchronized block.
  • Synchronization method: public synchronized 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. Only later blocked threads can obtain the lock and continue to execute.
  • Defect: declaring a large method synchronized will affect efficiency

Synchronization block:

  • 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 [explained in reflection]
  • Synchronization monitor execution
    • 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

Problem solving:

Add synchronized before the method

//Unsafe ticket buying
//Thread unsafe
public class UnsafeBuy {
    public static void main(String[] args) {
        BuyTicket station=new BuyTicket();

        new Thread(station,"Xiao Ming").start();
        new Thread(station,"I").start();
        new Thread(station,"Qin Dynasty").start();
    }

}

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

    @Override
    public void run() {
        //Buy a ticket
        while (flag){
            buy();
        }
    }
    //The synchronized synchronization method locks this
    private  synchronized void buy(){
        //Judge whether there are tickets
        if(ticketNums<=0){
            flag=false;
            return;
        }
        //Analog delay
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Buy a ticket
        System.out.println(Thread.currentThread().getName()+"Get"+ticketNums--);
    }
}

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-KwNV4aFF-1636557470635)(E: \ desktop \ document \ javaweb \ multithreaded. assets\image-20211110200812079.png)]

synchronized the default lock is this, and the object of the lock is the amount of change

//Unsafe withdrawal
//Two people go to the bank to withdraw money and open an account
public class UnsafeBank {
    public static void main(String[] args) {
        //account
        Account account=new Account(100,"Marriage fund");
        Drawing you=new Drawing(account,50,"you");
        Drawing girlFrend=new Drawing(account,100,"girlFrend");
        you.start();
        girlFrend.start();

    }

}

//account
class Account{
    int money;//balance
    String name;//Card name

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

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

    public Drawing(Account account,int drawingMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
    }
    //Withdraw money
//synchronized the default lock is this
    @Override
    public void  run() {
        synchronized (account){

            //Judge whether there is money
            if(account.money-drawingMoney<0){
                System.out.println(Thread.currentThread().getName()+"There's not enough money to withdraw");
                return;
            }
            //sleep can amplify the occurrence of problems
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //Card balance = balance - you get money
            account.money=account.money-drawingMoney;
            //The money in your hand
            nowMoney =nowMoney+drawingMoney;

            System.out.println(account.name+"The balance is:"+account.money);
            //Thread.currentThread().getName()=this.getName()
            System.out.println(this.getName()+"Money in hand:"+nowMoney);
        }
    }
}

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-apg3rGn3-1636557470637)(E: \ desktop \ document \ javaweb \ multithreaded. assets\image-20211110201347348.png)]

12. Deadlock

//Deadlock: multiple threads hold each other's required resources to form a deadlock
public class DeadLock {
    public static void main(String[] args) {
        Makeup g1=new Makeup(0,"Review noodle restaurant");
        Makeup g2=new Makeup(1,"Snow White");
        g1.start();
        g2.start();
    }
}
//Lipstick
class Lipstick{

}

//mirror
class Mirror{

}
class Makeup extends Thread{

    //There is only one resource needed. Use static to ensure that there is only one
    static Lipstick lipstick=new Lipstick();
    static Mirror mirror=new Mirror();

    int choice;//choice
    String girlName;//People who use cosmetics

    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 (lipstick){//Get lipstick lock
                System.out.println(this.girlName+"Get lipstick lock");
                Thread.sleep(1000);
                synchronized (mirror){//Want to get a 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");
                Thread.sleep(1000);
                synchronized (lipstick){//I want lipstick in a second
                    System.out.println(this.girlName+"Get lipstick lock");
                }
            }
        }
    }

}

[the external chain image transfer fails, and the source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-rdQ4TlKm-1636557470638)(E: \ desktop \ document \ javaweb \ multithreaded. assets\image-20211110204429224.png)], resulting in a deadlock

//Deadlock: multiple threads hold each other's required resources to form a deadlock
public class DeadLock {
    public static void main(String[] args) {
        Makeup g1=new Makeup(0,"Review noodle restaurant");
        Makeup g2=new Makeup(1,"Snow White");
        g1.start();
        g2.start();
    }
}
//Lipstick
class Lipstick{

}

//mirror
class Mirror{

}
class Makeup extends Thread{

    //There is only one resource needed. Use static to ensure that there is only one
    static Lipstick lipstick=new Lipstick();
    static Mirror mirror=new Mirror();

    int choice;//choice
    String girlName;//People who use cosmetics

    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 (lipstick){//Get lipstick lock
                System.out.println(this.girlName+"Get lipstick lock");
                Thread.sleep(1000);
            }
            synchronized (mirror){//Want to get a 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");
                Thread.sleep(2000);
            }
            synchronized (lipstick){//I want lipstick in a second
                System.out.println(this.girlName+"Get lipstick lock");
            }
        }
    }

}

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-WCb2ku2l-1636557470639)(E: \ desktop \ document \ javaweb \ multithreaded. assets\image-20211110204357162.png)]

Four necessary conditions for deadlock generation:

  1. Mutex 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 until they are used up at the end of the year.
  4. Circular waiting condition: a circular waiting resource relationship is formed between several processes.

Note: as long as you find a way to break one or more of them, you can avoid deadlock

13. Lock

  • Since JDK 5.0, Java has provided a more powerful thread synchronization mechanism -- synchronization is achieved by explicitly defining synchronization Lock objects. Synchronous locks use Lock objects as.
  • The java.util.concurrent.locks.Lock interface is a tool that controls multiple threads to access shared resources. Locks provide 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, which can explicitly add and release locks.

ReentrantLock reentrant lock

//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();
    }

}

//Test lock

class TestLock2 implements Runnable{
    int ticketNums=10;
    @Override
    public void run() {
        while(true){
            if(ticketNums>0){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(ticketNums--);
            }else{
                break;
            }
        }
    }
}

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-JpLjRjKQ-1636557470640)(E: \ desktop \ document \ javaweb \ multithreaded. assets\image-20211110210329899.png)]

import java.util.concurrent.locks.ReentrantLock;

//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();
    }

}

//Test lock

class TestLock2 implements Runnable{
    int ticketNums=10;
    //Define lock 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();
            }

        }
    }
}

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-o7n3MGuQ-1636557470641)(E: \ desktop \ document \ javaweb \ multithreaded. assets\image-20211110210741397.png)] [the external chain image transfer fails. The source station may have an anti-theft mechanism. It is recommended to save the image and upload it directly (img-kwG4Srlr-1636557470642)(E: \ desktop \ document \ javaweb \ multithreading. assets\image-20211110210906842.png)]

14. 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, have better performance, and have better scalability (provide more subclasses)
  • Priority:
    • Lock > synchronize code block (it has entered the method body and allocated corresponding resources) > synchronize method (outside the method body)

15. Thread collaboration

Producer consumer model

  • Suppose only one product can be stored in the warehouse, the producer puts the produced products into the warehouse, and the consumer takes the products from the warehouse for consumption
  • If there is no product in the warehouse, the producer will put the product into the warehouse, otherwise stop production and wait until the product in the warehouse is taken away by the consumer
  • If there is a product in the warehouse, the consumer can take the product away for consumption, otherwise stop consumption and wait until the product is put in the warehouse again

This is a thread synchronization problem. Producers and consumers share the same resource, and producers and consumers are interdependent and conditional on each other

  • For producers, they should inform consumers to wait before producing products, and after producing products, they need to inform consumers to consume immediately
  • For consumers, after consumption, they should inform producers that they have finished consumption and need to produce new products for consumption
  • In the producer consumer problem, synchronized is not enough
    • synchronized prevents concurrent updates to the same shared resource, enabling synchronization
    • synchronized cannot be used for message passing (Communication) between different threads

Therefore, Java provides several methods to solve the communication problem between threads

Method nameeffect
wait()It means that the thread waits until other threads notify it. Unlike sleep, it will release the lock
wait(long timeout)Specifies the number of milliseconds to wait
notify()Wake up a waiting thread
nofityAll()Wake up all threads calling the wait() method on the same object, and the threads with high priority are scheduled first

Note: all methods of Object class can only be used in synchronization methods or synchronization code blocks, otherwise an exception IIIegalMoniTorStateException will be thrown

Concurrent collaboration model "producer / consumer model" - > management process method

  • Producer: module responsible for production data (may be method, object, thread, process);
  • Consumer: module responsible for processing data (may be method, object, thread, process);
  • Buffer: consumers cannot directly use the producer's data. There is a "buffer" between them
//Test: producer consumer model -- > solution using cache: pipe process method
//Producer, consumer, product, buffer
public class TestPC {
    public static void main(String[] args) {
        SynContainer container=new SynContainer();
        new Priductor(container).start();
        new Consumer(container).start();

    }

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

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

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

//product
class Chicken{
    int id;//Product number

    public Chicken(int id) {
        this.id = id;
    }
}

//buffer
class SynContainer{
    //A container size is required
    Chicken[] chickens=new Chicken[10];
    //Container counter
    int count=0;

    //The producer puts in the product
    public synchronized void push(Chicken chicken){
        //If the container is full, it needs to wait for consumers to consume
        if (count==chickens.length){
            //Inform consumers to consume and producers to wait

        }
        //If it is not full, we need to throw in the product
        chickens[count]=chicken;
        count++;
        //Consumers can be notified of consumption
    }
    //Consumer products
    public synchronized Chicken pop(){
        //Judge whether it can be consumed
        if (count==0){
            //Wait for producers to produce, consumers to wait
        }
        //If you can consume
        count--;
        Chicken chicken=chickens[count];

        //When finished, inform the producer to produce
        return chicken;
    }
}

The producer puts the produced data into the buffer, and the consumer takes out the data from the buffer

Signal lamp method

//Test producer consumer problem 2: signal lamp method, flag bit solution
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){
        this.tv=tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if (i%2==0){
                this.tv.play("Happy base camp");
            }else{
                this.tv.play("Tiktok");
            }

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

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

}
//Products -- > Programs
class TV{
    //The actors performed and the audience waited
    //The audience watched and the actors waited
    String voice;//A performance
    boolean flag=true;

    //perform
    public synchronized void play(String voice){
        if (!flag){
            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){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Watched:"+voice);
        //Inform the actors to perform
        this.notifyAll();
        this.flag=!this.flag;
    }
}

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-UDs4huSy-1636557470644)(E: \ desktop \ document \ javaweb \ multithreaded. assets\image-20211110222411684.png)]

16. Use thread pool

  1. Background: resources that are often created and destroyed and used heavily, such as threads in concurrency, have a great impact on performance.
  2. Idea: create several threads in advance, put them into the thread pool, get them directly when using them, and put them back into the pool after use. It can avoid frequent creation, destruction and reuse. It is similar to public transportation in life.
  3. benefit
    • Improved response time (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: size of the core pool maximumPoolSize: maximum number of threads
      • keepAliveTime: when the thread has no task, how long will it last at most and then terminate
  4. JDK 5.0 provides APLS related to thread pool: executorservice and Executors
  5. ExecutorService: real thread pool interface. Common subclass ThreadPoolExecutor
    1. Void execute (Runnable command): executes a task / command without a return value. It is generally used to execute Runnable
    2. Future submit(Callable task): execute a task with a return value, and generally execute a Callable task
    3. void shutdown(): closes the connection pool
  6. Executors: tool class and factory class of thread pool, which are used to create and return different types of thread pools
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//Test thread pool
public class TestPool {
    public static void main(String[] args) {
        //1. Create a service and a thread pool. The parameter is the size of the thread pool
        ExecutorService service= Executors.newFixedThreadPool(10);
        //implement
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        //2. Close the link
        service.shutdown();
    }
}

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

    }
}

17. Summary

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

//Review and summarize thread creation
public class ThreaadNew {
    public static void main(String[] args) {
        new MyThread1().start();
        new Thread(new MyThread2()).start();

        FutureTask<Integer> futureTask=new FutureTask(new MyThread3());
        new Thread(futureTask).start();
        try {
            Integer integer=futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

//1. Inherit Thread class
class MyThread1 extends Thread{
    @Override
    public void run() {
        System.out.println("MyThreadd1");
    }
}
//2. Implement Runnable interface
class MyThread2 implements Runnable{
    @Override
    public void run() {
        System.out.println("MyThreadd2");
    }
}

//3. Implement Callable interface
class MyThread3 implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("MyThreadd3");
        return 100;
    }
}

Thread synchronized

Thread extension

lock

xecutorService service= Executors.newFixedThreadPool(10);
//Execute
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//2. Close the link
service.shutdown();
}
}

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

}

}

# 17. Summary

~~~java
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

//Review and summarize thread creation
public class ThreaadNew {
    public static void main(String[] args) {
        new MyThread1().start();
        new Thread(new MyThread2()).start();

        FutureTask<Integer> futureTask=new FutureTask(new MyThread3());
        new Thread(futureTask).start();
        try {
            Integer integer=futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

//1. Inherit Thread class
class MyThread1 extends Thread{
    @Override
    public void run() {
        System.out.println("MyThreadd1");
    }
}
//2. Implement Runnable interface
class MyThread2 implements Runnable{
    @Override
    public void run() {
        System.out.println("MyThreadd2");
    }
}

//3. Implement Callable interface
class MyThread3 implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("MyThreadd3");
        return 100;
    }
}

Thread synchronized

Thread extension

lock

Topics: Java Back-end