1. Producer and consumer issues
Producer and consumer issues:
- Only one product can be stored in the warehouse. The producer puts the produced products into the warehouse, and the consumer consumes the products in the warehouse;
- If there is no product in the warehouse, the producer puts the product into the warehouse. Otherwise, stop production and wait until the products in the warehouse are taken away by consumers;
- If there are products in the warehouse, consumers can take them away for consumption. Otherwise, stop consumption and wait until the product is put into the warehouse again.
This is a thread synchronization problem: producers and consumers share the same resource, and producers and consumers depend on and condition each other.
- For producers: before producing products, consumers should be notified to wait, and after producing products, consumers need to be notified to consume immediately;
- For consumers: after consumption, it is necessary to inform producers that consumption has ended and that new products need to be produced for consumption.
In the issue of producers and consumers, 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
2. Thread communication
Java provides several methods to solve the communication problem between threads:
Method name | effect |
---|---|
wait() | Indicates that the thread waits until notified by other threads; Unlike the sleep() method, it releases the lock |
wail(long timeout) | Number of milliseconds to wait |
notify() | Wake up a waiting thread |
notifyAll() | Wake up all threads calling the wait() method on the same object, and the threads with high priority are scheduled first |
[note] the above methods are all methods in the Object class, which can only be invoked in synchronous or synchronous code blocks. Otherwise, an IllegalMonitorStateException is thrown
There are two solutions to the above "producer consumer" problem: pipe process method and signal lamp method
2.1 tube pass method
Principle of pipe process method: the producer puts the produced data into the buffer, and the consumer takes out the data from the buffer
- Producer: the module responsible for production data (method, thread, process);
- Consumer: the module responsible for consuming data (method, thread, process);
- Buffer: consumers cannot directly use the producer's data. There is a "buffer" between them.
producer:
class Producer extends Thread { private SynContainer container; public Producer(SynContainer container) { this.container = container; } @Override public void run() { for (int i = 1; i < 101; i++) { container.push(new Product(i)); System.out.println("Produced the second" + i + "Products"); } } }
consumer:
class Consumer extends Thread { private SynContainer container; public Consumer(SynContainer container) { this.container = container; } @Override public void run() { for (int i = 1; i < 101; i++) { System.out.println("Consumed the second" + container.pop().getNum() + "Products"); } } }
Products:
class Product { // number private int num; public Product(int num) { this.num = num; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } }
buffer:
class SynContainer { // Container size private Product[] products = new Product[10]; // Container counter private int count = 0; public synchronized void push(Product product) { if (count == products.length) { // Inform consumers to consume and producers to wait try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // Producers produce, consumers wait products[count] = product; count++; // Inform consumers of consumption this.notifyAll(); } public synchronized Product pop() { if (count == 0) { // Inform producers to produce and consumers to wait try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // Consumer consumption count--; Product p = products[count]; // Inform the producer of production this.notifyAll(); return p; } }
Test:
public class TestPc { public static void main(String[] args) { SynContainer container = new SynContainer(); new Producer(container).start(); new Consumer(container).start(); } }
2.2 signal lamp method
Principle of signal lamp method: it is solved through sign bit
producer:
class Player extends Thread { private 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("Jitter: tiktok: record the good life"); } } } }
consumer:
class Watcher extends Thread { private Tv tv; public Watcher(Tv tv) { this.tv = tv; } @Override public void run() { for (int i = 0; i < 20; i++) { this.tv.watch(); } } }
Products:
class Tv { // program private String voice; // The actor performs and the audience waits for T // The audience watched and the actors waited for F private 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); this.voice = voice; this.flag = !this.flag; // Inform the audience to watch this.notifyAll(); } // watch public synchronized String 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; return voice; } }
Test:
public class TestPc2 { public static void main(String[] args) { Tv tv = new Tv(); new Player(tv).start(); new Watcher(tv).start(); } }