java thread communication

Keywords: Java Back-end

Multithreaded

Thread Synchronization

1. Methods involved

  • wait (): Once this method is executed, the current thread is blocked and the synchronization monitor is released
  • notify(): Once this method is executed, a process being waited is waked up, and if more than one thread is waiting, a higher priority thread is waked up
  • notifyAll(): Once this method is executed, all wait ed threads will be awakened

2. Description

  • 1.wait(), notify(), notifyAll() three methods must be used in the synchronization block or synchronization method
  • Callers of the 2.wait(), notify(), and notifyAll() methods must synchronize the code block or synchronization monitor calls in the synchronization method at the same time. Otherwise, IllegalMonitorSTATEexception exception will occur
  • 3.wait(), notify(), notifyAll() are defined in the java.lang.Object class

3. Examples

An example of thread communication: printing 1-100 with two threads. Alternating printing with thread1 and thread2

class Number implements Runnable{

    private int number = 1;

    @Override
    public void run() {
        while(true){
            synchronized (this) {
                // Wake Up Process
                notify();

                if (number <= 100) {
                    System.out.println(Thread.currentThread().getName() + ":" + number);
                    number++;

                    try {
                        //Causes the thread calling the following wait() method to become blocked
                        wait();
                        //wait releases the lock
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                } else {
                    break;
                }
            }
        }
    }
}

public class CommunicationTest {
    public static void main(String[] args) {
        Number number = new Number();
        Thread t1 = new Thread(number);
        Thread t2 = new Thread(number);

        t1.setName("Thread 1");
        t2.setName("Thread 2");

        t1.start();
        t2.start();
    }
}

Interview Question: What are the similarities and differences between sleep () and wait ()?

  • Same point: once a method is executed, the current thread can be blocked
  • The differences are as follows: 1) The positions of the two method declarations are different: sleep () is declared in the Thread class and wait () in the Object class.
    1. The scope of the call varies: sleep () can be called in any scenario you want. wait() must be used in a synchronization block or synchronization method
    2. About whether to release the synchronization monitor: If both methods are used in the synchronization block or synchronization method, sleep () will not release the lock, wait () will release the lock
    3. The location of the two method declarations is different: sleep () in the Thread class and wait () in the Object class.

Classic example: producer/consumer problem

The Productor delivers the product to the Clerk and the Customer takes the product from the clerk, thinking that the clerk can only hold a fixed number of products at a time. (e.g. 20) If a producer tries to produce more products, the shop assistant will ask the producer to stop and notify the producer to continue production if there is space in the store. If there is no product in the store, the shop assistant will tell the consumer to wait and if there is a product in the store, notify the consumer to take the product.
Two problems may arise here:

  1. When a producer is faster than a consumer, the consumer will miss some data and miss it.
  2. When consumers are faster than producers, consumers get the same data

Analysis:

  • 1. Is it a multi-threaded problem? Yes, producer thread, consumer thread
  • 2. Is there shared data? Yes, the shop assistant (or product)
  • 3. How to resolve thread security? There are three ways to synchronize
  • 4. Do you want to design communication between threads?
package day9.tenone;

class Clerk{
	//product
    private int produceCount = 0;

    //yield a product
    public synchronized void produceProduct() {
        if (produceCount < 20){
            produceCount++;
            System.out.println(Thread.currentThread().getName()+":Start production" +produceCount+ "Products");
            notify();
        }else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    //Consumer Products
    public synchronized void consumeProduct() {
        if (produceCount > 0){
            System.out.println(Thread.currentThread().getName()+":Start Consuming" +produceCount+ "Products");
            produceCount--;
            notify();
        }else {
            //wait for
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

class Producer extends Thread{
    //Producer
    private Clerk clerk;

    public Producer(Clerk clerk){
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(getName()+":Start production....");
        
        while (true){
            try {
                sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            clerk.produceProduct();
        }
    }
}

class Consumer extends Thread{
    private Clerk clerk;

    public Consumer(Clerk clerk){
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(getName()+":Start Consumer Products....");

        while (true){
            try {
                sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            clerk.consumeProduct();
        }
    }
}

public class ProductTest {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        Producer p1 = new Producer(clerk);
        p1.setName("Producer 1");

        Consumer c1 = new Consumer(clerk);
        c1.setName("Consumer 1");

        p1.start();
        c1.start();
    }

}

Posted by holiks on Fri, 12 Nov 2021 12:37:56 -0800