day14 multithreading 01

Posted by artacus on Wed, 01 Dec 2021 05:11:47 +0100

1. Implement multithreading

1.1 simple understanding of multithreading [understanding]

It refers to the technology that multiple threads execute concurrently from software or hardware.
Computers with multithreading capability can execute multiple threads at the same time due to hardware support, so as to improve performance.

[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-ULWl6Gp5-1638279149657)(.\img( simply understand multithreading. png)]

1.2 concurrency and parallelism [understanding]

  • Parallelism: multiple instructions are executed simultaneously on multiple CPU s at the same time.

    [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-DX9TIVmW-1638279149660)(.\img__ parallel. png)]

  • Concurrency: at the same time, multiple instructions are executed alternately on a single CPU.

    [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-A6oDRqy2-1638279149661)(.\img concurrent. png)]

1.3 process and thread [understanding]

  • Process: is a running program

    Independence: a process is a basic unit that can run independently. It is also an independent unit for system resource allocation and scheduling
    Dynamic: the essence of a process is an execution process of a program. A process is produced and dies dynamically
    Concurrency: any process can execute concurrently with other processes

  • Thread: it is a single sequential control flow in a process and an execution path

    Single thread: if a process has only one execution path, it is called a single threaded program

    Multithreading: if a process has multiple execution paths, it is called a multithreaded program

    [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-eHjR9gpE-1638279149662)(.\img multithreading example. png)]

1.4 multithreading mode 1: inherit Thread class [application]

  • Method introduction

    Method nameexplain
    void run()After the thread is started, this method will be called and executed
    void start()When this thread starts executing, the Java virtual opportunity calls the run method ()
  • Implementation steps

    • Define a class MyThread to inherit the Thread class
    • Override the run() method in the MyThread class
    • Create an object of the MyThread class
    • Start thread
  • Code demonstration

    public class MyThread extends Thread {
        @Override
        public void run() {
            for(int i=0; i<100; i++) {
                System.out.println(i);
            }
        }
    }
    public class MyThreadDemo {
        public static void main(String[] args) {
            MyThread my1 = new MyThread();
            MyThread my2 = new MyThread();
    
    //        my1.run();
    //        my2.run();
    
            //void start() causes this thread to start execution; The Java virtual machine calls the run method of this thread
            my1.start();
            my2.start();
        }
    }
    
  • Two small problems

    • Why override the run() method?

      Because run() is used to encapsulate the code executed by the thread

    • What is the difference between the run() method and the start() method?

      run(): encapsulates the code executed by the thread. It is called directly, which is equivalent to the call of ordinary methods

      start(): start the thread; The run() method of this thread is then called by the JVM

1.5 implementation of multithreading mode 2: implementation of Runnable interface [application]

  • Thread construction method

    Method nameexplain
    Thread(Runnable target)Assign a new Thread object
    Thread(Runnable target, String name)Assign a new Thread object
  • Implementation steps

    • Define a class MyRunnable to implement the Runnable interface
    • Override the run() method in the MyRunnable class
    • Create an object of the MyRunnable class
    • Create an object of Thread class and take the MyRunnable object as the parameter of the construction method
    • Start thread
  • Code demonstration

    public class MyRunnable implements Runnable {
        @Override
        public void run() {
            for(int i=0; i<100; i++) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
    public class MyRunnableDemo {
        public static void main(String[] args) {
            //Create an object of the MyRunnable class
            MyRunnable my = new MyRunnable();
    
            //Create an object of Thread class and take the MyRunnable object as the parameter of the construction method
            //Thread(Runnable target)
    //        Thread t1 = new Thread(my);
    //        Thread t2 = new Thread(my);
            //Thread(Runnable target, String name)
            Thread t1 = new Thread(my,"Tank");
            Thread t2 = new Thread(my,"aircraft");
    
            //Start thread
            t1.start();
            t2.start();
        }
    }
    

1.6 implementation of multithreading mode 3: implementation of Callable interface [application]

  • Method introduction

    Method nameexplain
    V call()Calculate the result. If the result cannot be calculated, an exception will be thrown
    FutureTask(Callable callable)Create a FutureTask and execute the given Callable once it is run
    V get()If necessary, wait for the calculation to complete, and then obtain its results
  • Implementation steps

    • Define a class MyCallable to implement the Callable interface
    • Override the call() method in the MyCallable class
    • Create an object of the MyCallable class
    • Create the FutureTask object of the implementation class of Future, and take the MyCallable object as the parameter of the construction method
    • Create an object of Thread class and take FutureTask object as the parameter of construction method
    • Start thread
    • Then call the get method to get the result after the thread ends.
  • Code demonstration

    public class MyCallable implements Callable<String> {
        @Override
        public String call() throws Exception {
            for (int i = 0; i < 100; i++) {
                System.out.println("Confess to the girl" + i);
            }
            //The return value represents the result after the thread runs
            return "promise";
        }
    }
    public class Demo {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            //After the thread is started, you need to execute the call method inside
            MyCallable mc = new MyCallable();
    
            //Thread t1 = new Thread(mc);
    
            //You can get the result after the Thread is executed. You can also pass it to the Thread object as a parameter
            FutureTask<String> ft = new FutureTask<>(mc);
    
            //Create thread object
            Thread t1 = new Thread(ft);
    
            String s = ft.get();
            //Open thread
            t1.start();
    
            //String s = ft.get();
            System.out.println(s);
        }
    }
    
  • Comparison of three implementation methods

    • Implement Runnable and Callable interfaces
      • Advantages: strong extensibility. You can inherit other classes while implementing this interface
      • Disadvantages: the programming is relatively complex and the methods in the Thread class cannot be used directly
    • Inherit Thread class
      • Benefits: programming is relatively simple. You can directly use the methods in the Thread class
      • Disadvantages: poor extensibility, unable to inherit other classes

1.7 setting and obtaining thread name [ application ]

  • Method introduction

    Method nameexplain
    void setName(String name)Change the name of this thread to equal the parameter name
    String getName()Returns the name of this thread
    Thread currentThread()Returns a reference to the thread object currently executing
  • Code demonstration

    public class MyThread extends Thread {
        public MyThread() {}
        public MyThread(String name) {
            super(name);
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(getName()+":"+i);
            }
        }
    }
    public class MyThreadDemo {
        public static void main(String[] args) {
            MyThread my1 = new MyThread();
            MyThread my2 = new MyThread();
    
            //void setName(String name): change the name of this thread to be equal to the parameter name
            my1.setName("high-speed rail");
            my2.setName("aircraft");
    
            //Thread(String name)
            MyThread my1 = new MyThread("high-speed rail");
            MyThread my2 = new MyThread("aircraft");
    
            my1.start();
            my2.start();
    
            //static Thread currentThread() returns a reference to the thread object currently executing
            System.out.println(Thread.currentThread().getName());
        }
    }
    

1.8 thread sleep [ application ]

  • correlation method

    Method nameexplain
    static void sleep(long millis)Causes the currently executing thread to stay (pause execution) for the specified number of milliseconds
  • Code demonstration

    public class MyRunnable implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                System.out.println(Thread.currentThread().getName() + "---" + i);
            }
        }
    }
    public class Demo {
        public static void main(String[] args) throws InterruptedException {
            /*System.out.println("Before going to bed ");
            Thread.sleep(3000);
            System.out.println("Wake up ");*/
    
            MyRunnable mr = new MyRunnable();
    
            Thread t1 = new Thread(mr);
            Thread t2 = new Thread(mr);
    
            t1.start();
            t2.start();
        }
    }
    

1.9 thread priority [ application ]

  • Thread scheduling

    • Two scheduling modes

      • Time sharing scheduling model: all threads use the right to use the CPU in turn, and evenly allocate the time slice of CPU occupied by each thread
      • Preemptive scheduling model: give priority to the threads with high priority to use CPU. If the threads have the same priority, one will be selected randomly. The threads with high priority will obtain more CPU time slices
    • Java uses a preemptive scheduling model

    • Randomness

      If the computer has only one CPU, then the CPU can only execute one instruction at a certain time. Only when the thread gets the CPU time slice, that is, the right to use, can it execute the instruction. Therefore, the execution of multithreaded programs is random, because it is not certain who grabs the right to use the CPU

      [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-msQnwJjP-1638279149663)(.\img multi thread example picture. png)]

  • Priority correlation method

    Method nameexplain
    final int getPriority()Returns the priority of this thread
    final void setPriority(int newPriority)Change the priority of this thread. The default priority of this thread is 5; Thread priority ranges from 1 to 10
  • Code demonstration

    public class MyCallable implements Callable<String> {
        @Override
        public String call() throws Exception {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + "---" + i);
            }
            return "Thread execution is complete";
        }
    }
    public class Demo {
        public static void main(String[] args) {
            //Priority: 1 - 10 default: 5
            MyCallable mc = new MyCallable();
    
            FutureTask<String> ft = new FutureTask<>(mc);
    
            Thread t1 = new Thread(ft);
            t1.setName("aircraft");
            t1.setPriority(10);
            //System.out.println(t1.getPriority());//5
            t1.start();
    
            MyCallable mc2 = new MyCallable();
    
            FutureTask<String> ft2 = new FutureTask<>(mc2);
    
            Thread t2 = new Thread(ft2);
            t2.setName("Tank");
            t2.setPriority(1);
            //System.out.println(t2.getPriority());//5
            t2.start();
        }
    }
    

1.10 daemon thread [application]

  • correlation method

    Method nameexplain
    void setDaemon(boolean on)Mark this thread as a daemon thread. When all running threads are daemon threads, the Java virtual machine will exit
  • Code demonstration

    public class MyThread1 extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(getName() + "---" + i);
            }
        }
    }
    public class MyThread2 extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(getName() + "---" + i);
            }
        }
    }
    public class Demo {
        public static void main(String[] args) {
            MyThread1 t1 = new MyThread1();
            MyThread2 t2 = new MyThread2();
    
            t1.setName("goddess");
            t2.setName("spare tire");
    
            //Set the second thread as the daemon thread
            //When the normal thread is executed, there is no need for the daemon thread to continue running
            t2.setDaemon(true);
    
            t1.start();
            t2.start();
        }
    }
    

2. Thread synchronization

2.1 ticket selling [ application ]

  • Case requirements

    A cinema is currently showing domestic blockbusters, with a total of 100 tickets, and it has three windows for ticket sales. Please design a program to simulate the ticket sales of the cinema

  • Implementation steps

    • Define a class SellTicket to implement the Runnable interface, which defines a member variable: private int = 100;

    • Rewrite the run() method in SellTicket class to realize ticket selling. The code steps are as follows

    • If the number of votes is greater than 0, sell the tickets and tell which window it is sold

    • After selling the tickets, the total number of votes will be reduced by 1

    • The ticket is sold out and the thread stops

    • Define a test class SellTicketDemo with the main method. The code steps are as follows

    • Create an object of SellTicket class

    • Create three Thread class objects, take the SellTicket object as the parameter of the construction method, and give the corresponding window name

    • Start thread

  • code implementation

    public class SellTicket implements Runnable {
        private int tickets = 100;
        //Rewrite the run() method in SellTicket class to realize ticket selling. The code steps are as follows
        @Override
        public void run() {
            while (true) {
                if(ticket <= 0){
                        //out of stock
                        break;
                    }else{
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        ticket--;
                        System.out.println(Thread.currentThread().getName() + "Selling tickets,Remaining" + ticket + "Ticket");
                    }
            }
        }
    }
    public class SellTicketDemo {
        public static void main(String[] args) {
            //Create an object of SellTicket class
            SellTicket st = new SellTicket();
    
            //Create three Thread class objects, take the SellTicket object as the parameter of the construction method, and give the corresponding window name
            Thread t1 = new Thread(st,"Window 1");
            Thread t2 = new Thread(st,"Window 2");
            Thread t3 = new Thread(st,"Window 3");
    
            //Start thread
            t1.start();
            t2.start();
            t3.start();
        }
    }
    

2.2 problems in ticket selling cases [understanding]

  • There is a problem selling tickets

    • The same ticket appeared many times

    • There were negative votes

  • Causes of problems

    Due to the randomness of thread execution, the execution right of cpu may be lost during ticket selling, resulting in problems

2.3 synchronizing code blocks to solve data security problems [application]

  • Conditions for safety problems

    • Is a multithreaded environment

    • Shared data

    • Multiple statements operate on shared data

  • How to solve the problem of multithreading security?

    • Basic idea: let the program have no security environment
  • How?

    • Lock the code for multiple statements to operate the shared data, so that only one thread can execute at any time

    • Java provides a way to synchronize code blocks

  • Sync code block format:

    synchronized(Any object) { 
    	Code for multiple statements to operate on shared data 
    }
    

    Synchronized (arbitrary object): it is equivalent to locking the code, and any object can be regarded as a lock

  • Advantages and disadvantages of synchronization

    • Benefits: it solves the data security problem of multithreading

    • Disadvantages: when there are many threads, each thread will judge the lock on synchronization, which is very resource-consuming and will virtually reduce the running efficiency of the program

  • Code demonstration

    public class SellTicket implements Runnable {
        private int tickets = 100;
        private Object obj = new Object();
    
        @Override
        public void run() {
            while (true) {
                synchronized (obj) { // Lock the code that may have security problems. Multiple threads must use the same lock
                    //When t1 comes in, it will lock this code
                    if (tickets > 0) {
                        try {
                            Thread.sleep(100);
                            //t1 rest 100ms
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //Window 1 is selling ticket 100
                        tickets--; 
                        System.out.println(Thread.currentThread().getName() + "The second is being sold" + tickets + "Ticket");
                    }
                }
                //When t1 comes out, the lock of this code is released
            }
        }
    }
    
    public class SellTicketDemo {
        public static void main(String[] args) {
            SellTicket st = new SellTicket();
    
            Thread t1 = new Thread(st, "Window 1");
            Thread t2 = new Thread(st, "Window 2");
            Thread t3 = new Thread(st, "Window 3");
    
            t1.start();
            t2.start();
            t3.start();
        }
    }
    

2.4 synchronization method to solve data security problems [application]

  • Format of synchronization method

    Synchronization method: add the synchronized keyword to the method

    Modifier  synchronized Return value type method name(Method parameters) { 
    	Method body;
    }
    

    What is the lock object of the synchronization method?

    ​ this

  • Static synchronization method

    Synchronous static method: add the synchronized keyword to the static method

    Modifier  static synchronized Return value type method name(Method parameters) { 
    	Method body;
    }
    

    What is the lock object for synchronous static methods?

    Class name.class

  • Code demonstration

    public class MyRunnable implements Runnable {
        private static int ticketCount = 100;
    
        @Override
        public void run() {
            while(true){
                if("Window one".equals(Thread.currentThread().getName())){
                    //Synchronization method
                    boolean result = synchronizedMthod();
                    if(result){
                        break;
                    }
                }
    
                if("Window II".equals(Thread.currentThread().getName())){
                    //Synchronous code block
                    synchronized (MyRunnable.class){
                        if(ticketCount == 0){
                           break;
                        }else{
                            try {
                                Thread.sleep(10);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            ticketCount--;
                            System.out.println(Thread.currentThread().getName() + "Selling tickets,Remaining" + ticketCount + "Ticket");
                        }
                    }
                }
    
            }
        }
    
        private static synchronized boolean synchronizedMthod() {
            if(ticketCount == 0){
                return true;
            }else{
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                ticketCount--;
                System.out.println(Thread.currentThread().getName() + "Selling tickets,Remaining" + ticketCount + "Ticket");
                return false;
            }
        }
    }
    
    //Create Demo test class
    public class Demo {
    	public static void main(String[] args) {
    		MyRunnable mr = new MyRunnable();
         
         	Thread t1 = new Thread(mr);
          	Thread t2 = new Thread(mr);
    
          	t1.setName("Window one");
          	t2.setName("Window II");
    
          	t1.start();
          	t2.start();
      }
    }
    
    

2.5 lock [application]

Although we can understand the Lock object problem of synchronization code blocks and synchronization methods, we do not directly see where the Lock is added and where the Lock is released. In order to more clearly express how to add and release the Lock, JDK5 provides a new Lock object Lock

Lock is an interface that cannot be instantiated directly. Its implementation class ReentrantLock is used to instantiate it here

  • ReentrantLock construction method

    Method nameexplain
    ReentrantLock()Create an instance of ReentrantLock
  • Locking and unlocking method

    Method nameexplain
    void lock()Acquire lock
    void unlock()Release lock
  • Code demonstration

    public class Ticket implements Runnable {
        //Number of tickets
        private int ticket = 100;
        private Object obj = new Object();
        private ReentrantLock lock = new ReentrantLock();
    
        @Override
        public void run() {
            while (true) {
                //synchronized (obj) {/ / multiple threads must use the same lock
                try {
                    lock.lock();
                    if (ticket <= 0) {
                        //out of stock
                        break;
                    } else {
                        Thread.sleep(100);
                        ticket--;
                        System.out.println(Thread.currentThread().getName() + "Selling tickets,Remaining" + ticket + "Ticket");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
                // }
            }
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            Ticket ticket = new Ticket();
    
            Thread t1 = new Thread(ticket);
            Thread t2 = new Thread(ticket);
            Thread t3 = new Thread(ticket);
    
            t1.setName("Window one");
            t2.setName("Window II");
            t3.setName("Window three");
    
            t1.start();
            t2.start();
            t3.start();
        }
    }
    

2.6 deadlock [understanding]

  • summary

    Thread deadlock refers to that two or more threads hold the resources required by each other, resulting in these threads being in a waiting state and unable to execute

  • Under what circumstances will deadlock occur

    1. Limited resources
    2. Synchronous nesting
  • Code demonstration

    public class Demo {
        public static void main(String[] args) {
            Object objA = new Object();
            Object objB = new Object();
    
            new Thread(()->{
                while(true){
                    synchronized (objA){
                        //Thread one
                        synchronized (objB){
                            System.out.println("Well off students are walking");
                        }
                    }
                }
            }).start();
    
            new Thread(()->{
                while(true){
                    synchronized (objB){
                        //Thread two
                        synchronized (objA){
                            System.out.println("Xiao Wei is walking");
                        }
                    }
                }
            }).start();
        }
    }
    

3. Producers and consumers

3.1 overview of producer and consumer models [application]

  • summary

    Producer consumer model is a very classic multi-threaded cooperation model. Understanding the producer consumer problem can make us have a deeper understanding of multi-threaded programming.

    The so-called producer consumer problem actually includes two types of threads:

    One is the producer thread used to produce data

    One is consumer thread, which is used to consume data

    In order to decouple the relationship between producers and consumers, shared data areas are usually used, just like a warehouse

    The producer's production data is directly placed in the shared data area, and does not need to care about the behavior of consumers

    Consumers only need to obtain data from the shared data area, and do not need to care about the behavior of producers

  • Wait and wake methods of Object class

    Method nameexplain
    void wait()Causes the current thread to wait until another thread calls the notify() method or notifyAll() method of the object
    void notify()Wake up a single thread waiting for the object monitor
    void notifyAll()Wake up all threads waiting for the object monitor

3.2 producer and consumer cases [application]

  • Case requirements

    • Table class (Desk): define variables representing the number of steamed stuffed buns, lock object variables, and variables marking whether there are steamed stuffed buns on the table

    • Producer class (Cooker): implement the Runnable interface, rewrite the run() method, and set the thread task

      1. Judge whether there are packages and decide whether the current thread executes

      2. If there are steamed stuffed buns, enter the waiting state. If there are no steamed stuffed buns, continue to execute and produce steamed stuffed buns

      3. After producing steamed stuffed buns, update the status of steamed stuffed buns on the table to awaken consumers to consume steamed stuffed buns

    • Consumer class (Foodie): implement the Runnable interface, rewrite the run() method, and set the thread task

      1. Judge whether there are packages and decide whether the current thread executes

      2. If there are no steamed stuffed buns, enter the waiting state. If there are steamed stuffed buns, consume steamed stuffed buns

      3. After consuming steamed stuffed buns, update the status of steamed stuffed buns on the table to wake up the producers to produce steamed stuffed buns

    • Test class (Demo): there is a main method. The code steps in the main method are as follows

      Create producer and consumer thread objects

      Open two threads respectively

  • code implementation

    public class Desk {
    
        //Define a tag
        //true means that there are hamburgers on the table. At this time, it is allowed to eat goods
        //false means that there are no hamburgers on the table. At this time, the chef is allowed to execute
        public static boolean flag = false;
    
        //Total number of hamburgers
        public static int count = 10;
    
        //Lock object
        public static final Object lock = new Object();
    }
    
    public class Cooker extends Thread {
    //    Producer steps:
    //            1. Judge whether there are hamburgers on the table
    //    If there is, wait. If not, it will be produced.
    //            2. Put the hamburger on the table.
    //            3. Wake up the waiting consumers and start eating.
        @Override
        public void run() {
            while(true){
                synchronized (Desk.lock){
                    if(Desk.count == 0){
                        break;
                    }else{
                        if(!Desk.flag){
                            //production
                            System.out.println("The cook is making hamburgers");
                            Desk.flag = true;
                            Desk.lock.notifyAll();
                        }else{
                            try {
                                Desk.lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
    }
    
    public class Foodie extends Thread {
        @Override
        public void run() {
    //        1. Judge whether there are hamburgers on the table.
    //        2. If not, wait.
    //        3. Eat if you have one
    //        4. After eating, there are no hamburgers on the table
    //                Wake up the waiting producers and continue production
    //        The total number of hamburgers is reduced by one
    
            //tricks:
                //1. while(true) loop
                //2. For synchronized locks, the lock object should be unique
                //3. Judge whether the shared data is over
                //4. Judge whether the shared data is over or not
            while(true){
                synchronized (Desk.lock){
                    if(Desk.count == 0){
                        break;
                    }else{
                        if(Desk.flag){
                            //have
                            System.out.println("The food is eating hamburgers");
                            Desk.flag = false;
                            Desk.lock.notifyAll();
                            Desk.count--;
                        }else{
                            //No, just wait
                            //What object is used as a lock, you must use this object to call wait and wake methods
                            try {
                                Desk.lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
    
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            /*Consumer steps:
            1,Judge whether there are hamburgers on the table.
            2,If not, wait.
            3,If you have it, eat it
            4,After eating, there are no hamburgers on the table
                    Wake up the waiting producers and continue production
            The total number of hamburgers is reduced by one*/
    
            /*Producer steps:
            1,Judge whether there are hamburgers on the table
            If there is, wait. If not, it will be produced.
            2,Put the hamburger on the table.
            3,Wake up the waiting consumers and start eating.*/
    
            Foodie f = new Foodie();
            Cooker c = new Cooker();
    
            f.start();
            c.start();
    
        }
    }
    

3.3 producer and consumer case optimization [application]

  • demand

    • The variables in the Desk class are encapsulated in an object-oriented manner
    • The constructor in the producer and consumer classes receives the Desk class object and then uses it in the run method
    • Create producer and consumer thread objects, and pass in Desk class objects in the constructor
    • Open two threads
  • code implementation

    public class Desk {
    
        //Define a tag
        //true means that there are hamburgers on the table. At this time, it is allowed to eat goods
        //false means that there are no hamburgers on the table. At this time, the chef is allowed to execute
        //public static boolean flag = false;
        private boolean flag;
    
        //Total number of hamburgers
        //public static int count = 10;
        //In the future, we will use this variable that must have a default value
       // private int count = 10;
        private int count;
    
        //Lock object
        //public static final Object lock = new Object();
        private final Object lock = new Object();
    
        public Desk() {
            this(false,10); // Call the parameter inside the empty parameter to assign a value to the member variable, and then you can use the member variable directly
        }
    
        public Desk(boolean flag, int count) {
            this.flag = flag;
            this.count = count;
        }
    
        public boolean isFlag() {
            return flag;
        }
    
        public void setFlag(boolean flag) {
            this.flag = flag;
        }
    
        public int getCount() {
            return count;
        }
    
        public void setCount(int count) {
            this.count = count;
        }
    
        public Object getLock() {
            return lock;
        }
    
        @Override
        public String toString() {
            return "Desk{" +
                    "flag=" + flag +
                    ", count=" + count +
                    ", lock=" + lock +
                    '}';
        }
    }
    
    public class Cooker extends Thread {
    
        private Desk desk;
    
        public Cooker(Desk desk) {
            this.desk = desk;
        }
    //    Producer steps:
    //            1. Judge whether there are hamburgers on the table
    //    If there is, wait. If not, it will be produced.
    //            2. Put the hamburger on the table.
    //            3. Wake up the waiting consumers and start eating.
    
        @Override
        public void run() {
            while(true){
                synchronized (desk.getLock()){
                    if(desk.getCount() == 0){
                        break;
                    }else{
                        //System.out.println("verify whether it is executed");
                        if(!desk.isFlag()){
                            //production
                            System.out.println("The cook is making hamburgers");
                            desk.setFlag(true);
                            desk.getLock().notifyAll();
                        }else{
                            try {
                                desk.getLock().wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
    }
    
    public class Foodie extends Thread {
        private Desk desk;
    
        public Foodie(Desk desk) {
            this.desk = desk;
        }
    
        @Override
        public void run() {
    //        1. Judge whether there are hamburgers on the table.
    //        2. If not, wait.
    //        3. Eat if you have one
    //        4. After eating, there are no hamburgers on the table
    //                Wake up the waiting producers and continue production
    //        The total number of hamburgers is reduced by one
    
            //tricks:
                //1. while(true) loop
                //2. For synchronized locks, the lock object should be unique
                //3. Judge whether the shared data is over
                //4. Judge whether the shared data is over or not
            while(true){
                synchronized (desk.getLock()){
                    if(desk.getCount() == 0){
                        break;
                    }else{
                        //System.out.println("verify whether it is executed");
                        if(desk.isFlag()){
                            //have
                            System.out.println("The food is eating hamburgers");
                            desk.setFlag(false);
                            desk.getLock().notifyAll();
                            desk.setCount(desk.getCount() - 1);
                        }else{
                            //No, just wait
                            //What object is used as a lock, you must use this object to call wait and wake methods
                            try {
                                desk.getLock().wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
    
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            /*Consumer steps:
            1,Judge whether there are hamburgers on the table.
            2,If not, wait.
            3,If you have it, eat it
            4,After eating, there are no hamburgers on the table
                    Wake up the waiting producers and continue production
            The total number of hamburgers is reduced by one*/
    
            /*Producer steps:
            1,Judge whether there are hamburgers on the table
            If there is, wait. If not, it will be produced.
            2,Put the hamburger on the table.
            3,Wake up the waiting consumers and start eating.*/
    
            Desk desk = new Desk();
    
            Foodie f = new Foodie(desk);
            Cooker c = new Cooker(desk);
    
            f.start();
            c.start();
    
        }
    }
    

3.4 basic use of blocking queue [understanding]

  • Blocking queue inheritance structure

    [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-moTvGNEe-1638279149664)(.\img_ blocking queue inheritance structure. png)]

  • Common BlockingQueue:

    ArrayBlockingQueue: the bottom layer is an array, bounded

    LinkedBlockingQueue: the bottom layer is a linked list, unbounded. But it is not really unbounded. The maximum is the maximum value of int

  • The core method of BlockingQueue:

    put(anObject): put the parameters into the queue. If they are not put in, they will be blocked

    take(): fetch the first data, otherwise it will be blocked

  • Code example

    public class Demo02 {
        public static void main(String[] args) throws Exception {
            // Object to create a blocking queue with a capacity of 1
            ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);
    
            // Storage element
            arrayBlockingQueue.put("hamburger");
    
            // Take element
            System.out.println(arrayBlockingQueue.take());
            System.out.println(arrayBlockingQueue.take()); // If you can't get it, it will block
    
            System.out.println("The program is over");
        }
    }
    

3.5 blocking queue realizes waiting wake-up mechanism [understanding]

  • Case requirements

    • Producer class (Cooker): implement the Runnable interface, rewrite the run() method, and set the thread task

      1. Receive a blocking queue object in the construction method

      2. In the run method, loop to add packets to the blocking queue

      3. Print and add results

    • Consumer class (Foodie): implement the Runnable interface, rewrite the run() method, and set the thread task

      1. Receive a blocking queue object in the construction method

      2. Loop through the run method to get the packets in the blocking queue

      3. Print the obtained results

    • Test class (Demo): there is a main method. The code steps in the main method are as follows

      Create blocking queue object

      Create producer thread and consumer thread objects, and construct the incoming blocking queue object in the method

      Open two threads respectively

  • code implementation

    public class Cooker extends Thread {
    
        private ArrayBlockingQueue<String> bd;
    
        public Cooker(ArrayBlockingQueue<String> bd) {
            this.bd = bd;
        }
    //    Producer steps:
    //            1. Judge whether there are hamburgers on the table
    //    If there is, wait. If not, it will be produced.
    //            2. Put the hamburger on the table.
    //            3. Wake up the waiting consumers and start eating.
    
        @Override
        public void run() {
            while (true) {
                try {
                    bd.put("hamburger");
                    System.out.println("The cook put in a hamburger");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    public class Foodie extends Thread {
        private ArrayBlockingQueue<String> bd;
    
        public Foodie(ArrayBlockingQueue<String> bd) {
            this.bd = bd;
        }
    
        @Override
        public void run() {
    //        1. Judge whether there are hamburgers on the table.
    //        2. If not, wait.
    //        3. Eat if you have one
    //        4. After eating, there are no hamburgers on the table
    //                Wake up the waiting producers and continue production
    //        The total number of hamburgers is reduced by one
    
            //tricks:
            //1. while(true) loop
            //2. For synchronized locks, the lock object should be unique
            //3. Judge whether the shared data is over
            //4. Judge whether the shared data is over or not
            while (true) {
                try {
                    String take = bd.take();
                    System.out.println("Eat goods will" + take + "Take it out and eat it");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            ArrayBlockingQueue<String> bd = new ArrayBlockingQueue<>(1);
    
            Foodie f = new Foodie(bd);
            Cooker c = new Cooker(bd);
    
            f.start();
            c.start();
        }
    }
    

Topics: Java JavaSE