Article catalog
1, Producer consumer
1. Overview of producer and consumer models
- 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

2. Producer and consumer cases
- 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 end //4. Judge whether the shared data is over Not over 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. Producer and consumer case optimization
- 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 end //4. Judge whether the shared data is over Not over 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(); } }
4. Basic use of blocking queue
- Blocking queue inheritance structure

- Common BlockingQueue:
ArrayBlockingQueue: the bottom layer is an array, bounded
LinkedBlockingQueue: the bottom layer is a linked list, unbounded But it's 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"); } }
5. The blocking queue implements the wake-up waiting mechanism
- 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 end //4. Judge whether the shared data is over Not over 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(); } }