[Big Data] Study Notes 1 Java SE Chapter 9 Multithreading 9.5 Waiting for Wakeup Mechanism

[Big Data] Study Notes

insert image description here

1 Java SE

Chapter 9 Multithreading

9.5 Waiting for wakeup mechanism
9.5.1 Inter-thread communication

Why deal with inter-thread communication:

Multiple threads are processing the same resource, but the processing actions (tasks of the threads) are different. When multiple threads execute concurrently, the CPU switches threads randomly by default. When we need multiple threads to complete a task together, and we want them to execute regularly, then some communication mechanism is needed between multiple threads. , can coordinate their work to help us achieve multi-threaded joint operation of a piece of data.

For example: thread A is used to generate buns, thread B is used to eat buns, buns can be understood as the same resource, and the actions processed by thread A and thread B are one for production and one for consumption. At this time, thread B must wait until thread A It can only be executed after it is completed, then thread communication is required between thread A and thread B, that is, waiting for the wake-up mechanism.

9.5.2 Waiting for wakeup mechanism

What is the waiting wake-up mechanism

This is a coordination mechanism between multiple threads . When it comes to threads, what we often think of is the competition (race) between threads , such as to compete for locks, but this is not the whole story, there will also be a cooperation mechanism between threads.

It is when a thread meets a certain condition, it enters the waiting state ( wait() / wait(time) ), waits for other threads to execute their specified code and then wakes it up ( notify() ); or you can specify wait Time, automatically wake up when the time is up; when there are multiple threads waiting, if necessary, you can use notifyAll() to wake up all waiting threads. wait/notify is a coordination mechanism between threads.

  1. wait: The thread is no longer active, no longer participates in scheduling, and enters the wait set, so it will not waste CPU resources and will not compete for locks. At this time, the thread state is WAITING or TIMED_WAITING. It also waits for other threads to perform a special action , that is, " notify " or when the waiting time is up, the thread waiting on this object is released from the wait set and re-enters the dispatch queue (ready queue) )middle
  2. notify: select a thread in the wait set of the notified object to release;
  3. notifyAll: Release all threads on the wait set of the notified object.

Notice:

The notified thread may not be able to resume execution immediately after being woken up, because the place where it was interrupted was in the synchronization block, and at this moment it no longer holds the lock, so she needs to try to acquire the lock again (possibly facing other threads) Competition), only after success can the execution be resumed at the place after the wait method was originally called.

Summarized as follows:

  • If the lock can be acquired, the thread changes from the WAITING state to the RUNNABLE (runnable) state;
  • Otherwise, the thread changes from the WAITING state to the BLOCKED (waiting for lock) state

The details that need to be paid attention to when calling the wait and notify methods

  1. The wait method and the notify method must be called by the same lock object. Because: the corresponding lock object can wake up the thread after the wait method called with the same lock object through notify.
  2. The wait method and the notify method belong to the methods of the Object class. Because: the lock object can be any object, and the class of any object inherits the Object class.
  3. The wait method and notify method must be used in a synchronous code block or a synchronous function. Because: these two methods must be called through the lock object.
9.5.3 The Producer and Consumer Problem

Waiting for the wake-up mechanism can solve the classic "producer and consumer" problem.

Producer-consumer problem (English: Producer-consumer problem), also known as limited buffer problem (English: Bounded-buffer problem), is a classic case of multi-thread synchronization problem. The problem describes what happens when two (multiple) threads sharing a fixed-size buffer - so-called "producers" and "consumers" - actually run. The main role of the producer is to generate a certain amount of data into the buffer, and then repeat the process. At the same time, the consumer is also consuming the data in the buffer. The key to this problem is to ensure that the producer will not add data when the buffer is full, and the consumer will not consume data when the buffer is empty.

There are actually two problems implied in the producer and consumer problem:

  • Thread safety problem: Because the producer and consumer share the data buffer, but this problem can be solved using synchronization.
  • Thread coordination problem:
    • To solve this problem, it is necessary to let the producer thread wait (wait) when the buffer is full, pause and enter the blocking state, and wait until the next time the consumer consumes the data in the buffer, notify (notify) the waiting thread to resume To the ready state, start adding data to the buffer again. Similarly, the consumer thread can also be allowed to enter the waiting (wait) when the buffer is empty, pause and enter the blocking state, wait until the producer adds data to the buffer, and then notify (notify) the waiting thread to return to the ready state. Such problems are solved through such a communication mechanism.

【1】One chef and one waiter problem

Case: There is a restaurant with a relatively small opening, which can only hold 10 servings of fast food. After the chef finishes cooking the fast food, he puts it on the workbench of the takeout opening, and the waiter takes out the fast food from the workbench to the customer. Now there is 1 cook and 1 waiter.

package com.dingjiaxiong.thread5;

/**
 * @Projectname: BigDataStudy
 * @Classname: TestCommunicate
 * @Author: Ding Jiaxiong
 * @Date:2023/4/27 16:12
 */

public class TestCommunicate {
    
    
    public static void main(String[] args) {
    
    
        // 1、创建资源类对象
        Workbench workbench = new Workbench();

        // 2、创建和启动厨师线程
        new Thread("厨师") {
    
    
            public void run() {
    
    
                while (true) {
    
    
                    workbench.put();
                }
            }
        }.start();

        // 3、创建和启动服务员线程
        new Thread("服务员") {
    
    
            public void run() {
    
    

                while (true) {
    
    
                    workbench.take();
                }
            }
        }.start();
    }

}

// 1、定义资源类
class Workbench {
    
    
    private static final int MAX_VALUE = 10;
    private int num;

    public synchronized void put() {
    
    
        if (num >= MAX_VALUE) {
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        num++;
        System.out.println(Thread.currentThread().getName() + "制作了一份快餐,现在工作台上有:" + num + "份快餐");
        this.notify();
    }

    public synchronized void take() {
    
    
        if (num <= 0) {
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        num--;
        System.out.println(Thread.currentThread().getName() + "取走了一份快餐,现在工作台上有:" + num + "份快餐");
        this.notify();
    }
}

insert image description here

【2】Multiple cooks and multiple waiters

Case: There is a restaurant with a relatively small opening, which can only hold 10 servings of fast food. After the chef finishes cooking the fast food, he puts it on the workbench of the takeout opening, and the waiter takes out the fast food from the workbench to the customer. Now there are multiple cooks and multiple waiters.

package com.dingjiaxiong.thread5;

/**
 * @Projectname: BigDataStudy
 * @Classname: TestCommunicate2
 * @Author: Ding Jiaxiong
 * @Date:2023/4/27 16:13
 */

public class TestCommunicate2 {
    
    
    public static void main(String[] args) {
    
    
        // 1、创建资源类对象
        WindowBoard windowBoard = new WindowBoard();

        // 2、创建和启动厨师线程
        // 3、创建和启动服务员线程
        Cook c1 = new Cook("张三", windowBoard);
        Cook c2 = new Cook("李四", windowBoard);
        Waiter w1 = new Waiter("小红", windowBoard);
        Waiter w2 = new Waiter("小绿", windowBoard);

        c1.start();
        c2.start();
        w1.start();
        w2.start();
    }

}

//1、定义资源类
class WindowBoard {
    
    
    private static final int MAX_VALUE = 10;
    private int num;

    public synchronized void put() {
    
    
        while (num >= MAX_VALUE) {
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        num++;
        System.out.println(Thread.currentThread().getName() + "制作了一份快餐,现在工作台上有:" + num + "份快餐");
        this.notifyAll();
    }

    public synchronized void take() {
    
    
        while (num <= 0) {
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        num--;
        System.out.println(Thread.currentThread().getName() + "取走了一份快餐,现在工作台上有:" + num + "份快餐");
        this.notifyAll();
    }
}


//2、定义厨师类
class Cook extends Thread {
    
    
    private WindowBoard windowBoard;

    public Cook(String name, WindowBoard windowBoard) {
    
    
        super(name);
        this.windowBoard = windowBoard;
    }

    public void run() {
    
    
        while (true) {
    
    
            windowBoard.put();
        }
    }
}


//3、定义服务员类
class Waiter extends Thread {
    
    
    private WindowBoard windowBoard;

    public Waiter(String name, WindowBoard windowBoard) {
    
    
        super(name);
        this.windowBoard = windowBoard;
    }

    public void run() {
    
    
        while (true) {
    
    
            windowBoard.take();
        }
    }
}

insert image description here

Guess you like

Origin blog.csdn.net/weixin_44226181/article/details/130480169