[Thread] Thread communication

Posted by freshneco on Sun, 07 Nov 2021 01:04:03 +0100

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

Topics: Java Back-end