Waiting and awakening mechanism between multiple threads in Java


Preface

Based on what we have learned before, we can use the multi-threading mechanism in java to simulate the process of buying tickets in a movie theater, but from the following figure we can see that the three threads belong to the same type of thread, and they are all performing the operation of buying tickets. . So how does java deal with the communication problems between different types of threads? Then it involves the wait and wake-up mechanism between java multi-threads.
Insert picture description here

Knowledge point: waiting for wake-up mechanism

1. Demand: to realize the communication between the production line and the consumption line, the realization effect is that the producer produces one and the consumer consumes one.

  • Producer's perspective: if resources have not been consumed yet, wait for no production and notify consumers to consume
  • From the perspective of consumers, if there are resources, consume, if there are no resources, wait and notify the producer to produce

2. Oject class

  • void notify ()
    wakes up a single thread waiting on this object monitor .
  • void notifyAll ()
    wakes up all threads waiting on this object monitor .
  • void wait ()
    causes the current thread to wait before other threads call the notify () method or notifyAll () method of this object.
  • void wait (long timeout)
    causes the current thread to wait before another thread calls the notify () method or notifyAll () method of this object, or exceeds the specified amount of time.

3. Code example

  • Conditions:
    1. Producer thread
    2. Consumer thread
    3. Circulation resources
public class 线程间等待唤醒机制 {
    
    
    public static void main(String[] args) {
    
    
        //创建共享资源
        Student student = new Student();
        //将资源传递给线程,所以线程之间是共享资源的
        SetThread  th1= new SetThread(student);
        GetThread th2 = new GetThread(student);
        th1.start();
        th2.start();

    }

}
//1.生产线程
class SetThread extends Thread{
    
    
    private Student student;
    int i=0;
    public SetThread(Student student) {
    
    
        this.student = student;
    }

    @Override
    public void run() {
    
    
        while (true){
    
    
            synchronized (student){
    
    
                //能够进入该代码,说明有资源,生产线程就应该等待
                if(student.flag){
    
    
                    try {
    
    
                        student.wait();
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }
                if (i % 2 == 0) {
    
    
                    student.name = "张三";
                    student.age = 19;
                } else {
    
    
                    student.name = "李四";
                    student.age = 23;
                }
                //更改标记
                student.flag=true;
                //通知消费线程去消费
                student.notify();
            }

            i++;
        }



    }
}
//2.消费线程
class GetThread extends Thread{
    
    
   private  Student student;
    public GetThread(Student student) {
    
    
        this.student=student;
    }

    @Override
    public void run() {
    
    
        while (true){
    
    
            //既然对象是一个,我们可以将其作为锁对象。这样保持两个同步代码块的锁一致
            synchronized (student){
    
    
                //如果没有资源,进入程序等待
                if(!student.flag){
    
    
                    try {
    
    
                        student.wait();//线程一旦调用等待wait()方法,就会释放锁,即线程没出同步代码块提前释放锁。下次被唤醒 ,从此处唤醒
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }

                }
                System.out.println(student.name + "," + student.age);
                //消费完资源后,更改标记,通知生产者生产
                student.flag=false;
                student.notify();
            }
        }

    }
}
//资源
class Student{
    
    
    public String name;
    public int age;
    //定义一个标记
    public boolean flag=false;//false表示没有资源,true表示有资源
}

Implementation effect chart:
Insert picture description here

4. The difference between sleep() method and wait() method

  • Common: Both can make the thread in a blocking state
  • wait() method : causes the current thread to be in a blocked state until another thread calls notify () or notifyAll () to wake up. To call this method, a lock object must be obtained, so this method can only be used in synchronization methods and synchronization code blocks Used in . ( Notify () also needs to be called in a synchronized method or synchronized code block ).Once the wait() method is executed, the lock will be released, and notify () can be used to wake up directly.
  • sleep() method :Once dormant, the lock will not be released (the amount of time must be set), and it can only be interrupted forcibly by calling Interreput() before time is reached.

operation

  • Use what you have learned and write code.
    Requirements: Write two threads, one thread prints 1-52, one thread prints AZ, and the print result is 12A34B56C78D-----5152Z (that is, two numbers and one letter).

  • Code answer

public class day23作业1 {
    
    
    public static void main(String[] args) {
    
    
        //创建共享资源
        PrintFunc printFunc = new PrintFunc();
        //将共享资源传入两个子线程中
        DigitalThread th1 = new DigitalThread(printFunc);
        LetterThread th2 = new LetterThread(printFunc);
        th1.start();
        th2.start();

    }
}
//1.数字线程
class DigitalThread extends Thread{
    
    
    int i=1;
    private PrintFunc printFunc;

    public DigitalThread(PrintFunc printFunc) {
    
    

        this.printFunc = printFunc;
    }

    @Override
    public void run() {
    
    
        while (i<=52){
    
    
            synchronized (printFunc){
    
    
                //进入这段代码,代表打印了数字
                if(printFunc.flag){
    
    
                    try {
    
    
                        printFunc.wait();
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }
                System.out.print(i);
                i++;
                System.out.print(i);
                //打印了数字,更改标志
                printFunc.flag=true;
                //通知字母线程打印
                printFunc.notify();
            }
            i++;
        }
    }
}
//2.字母线程
class LetterThread extends Thread{
    
    
    char ch='A';
    private PrintFunc printFunc;

    public LetterThread(PrintFunc printFunc) {
    
    
        this.printFunc = printFunc;
    }

    @Override
    public void run() {
    
    
        while (ch<=90){
    
    
            synchronized (printFunc){
    
    
                //进入该代码,表示尚未打印数字
                if(!printFunc.flag){
    
    
                    try {
    
    
                        printFunc.wait();
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }
                //打印了数字,开始打印字母
                System.out.print(ch);
                //更改标志
                printFunc.flag=false;
                printFunc.notify();
            }
            ch++;

        }
    }
}
//3.共享资源
class PrintFunc{
    
    
    //定义一个标签
    boolean flag=false;//false代表尚未打印数字
}
  • result
    Insert picture description here

Guess you like

Origin blog.csdn.net/m0_46988935/article/details/112916318