java 22 - 17 多线程之等待唤醒机制(接16)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 22 - 17 多线程之等待唤醒机制(接16)相关的知识,希望对你有一定的参考价值。

先来一张图,看看什么叫做等待唤醒机制

技术分享

 

接上一章的例子。

例子:学生信息的录入和获取

  * 资源类:Student 
  * 设置学生数据:SetThread(生产者)
  * 获取学生数据:GetThread(消费者)
  * 测试类:StudentDemo

 

* 资源类:Student (为了使用等待唤醒机制,添加了个布尔类型的变量,默认为flase)

1 public class Student {
2     String name;
3     int age;
4     boolean flag; // 默认情况是没有数据,如果是true,说明有数据
5 }

 

* 设置学生数据:SetThread(生产者)

 1 public class SetThread implements Runnable {
 2 
 3     private Student s;
 4     private int x = 0;
 5 
 6     public SetThread(Student s) {
 7         this.s = s;
 8     }
 9 
10     @Override
11     public void run() {
12         while (true) {
13             synchronized (s) {
14                 //判断有没有
15                 if(s.flag){
16                     try {
17                         s.wait(); //t1等着,释放锁
18                     } catch (InterruptedException e) {
19                         e.printStackTrace();
20                     }
21                 }
22                 
23                 if (x % 2 == 0) {
24                     s.name = "张三";
25                     s.age = 23;
26                 } else {
27                     s.name = "李四";
28                     s.age = 24;
29                 }
30                 x++; //x=1
31                 
32                 //修改标记
33                 s.flag = true;
34                 //唤醒线程
35                 s.notify(); //唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。
36             }
37             //t1有,或者t2有
38         }
39     }
40 }

 

* 获取学生数据:GetThread(消费者)

 1 public class GetThread implements Runnable {
 2     private Student s;
 3 
 4     public GetThread(Student s) {
 5         this.s = s;
 6     }
 7 
 8     @Override
 9     public void run() {
10         while (true) {
11             synchronized (s) {
12                 if(!s.flag){
13                     try {
14                         s.wait(); //t2就等待了。立即释放锁。将来醒过来的时候,是从这里醒过来的时候
15                     } catch (InterruptedException e) {
16                         e.printStackTrace();
17                     }
18                 }
19                 
20                 System.out.println(s.name + "---" + s.age);
21                 //张三---23
22                 //李四---24
23                 
24                 //修改标记
25                 s.flag = false;
26                 //唤醒线程
27                 s.notify(); //唤醒t1
28             }
29         }
30     }
31 }

 

* 测试类:StudentDemo

 1 public class StudentDemo {
 2     public static void main(String[] args) {
 3         //创建资源
 4         Student s = new Student();
 5         
 6         //设置和获取的类
 7         SetThread st = new SetThread(s);
 8         GetThread gt = new GetThread(s);
 9 
10         //线程类
11         Thread t1 = new Thread(st);
12         Thread t2 = new Thread(gt);
13 
14         //启动线程
15         t1.start();
16         t2.start();
17     }
18 }

 

来,依次分析这段代码:

①假设消费者GetThread先抢到了CPU的资源:

则先执行这段代码:

 1     public void run() {
 2         while (true) { //true,进来
 3             synchronized (s) {
 4                 if(!s.flag){ //因为是消费者先进来,所以里面没有“包子”,而s.flag的默认值是flase,这里取反,就true,进来
 5                     try {
 6                         s.wait(); //没“包子”,等待,并且释放锁。下次唤醒它的时候,是从这里唤醒,并不是从头开始执行
 7                     } catch (InterruptedException e) {
 8                         e.printStackTrace();
 9                     }
10                 }
11                 
12                 System.out.println(s.name + "---" + s.age);
13                 
14                
15                 s.flag = false;
16                 
17                 s.notify(); 
18             }
19         }
20     }

 

②由于消费者在等待,并且释放了锁。则消费者和生产者继续抢CPU的资源,而消费者抢到的话,依旧等待,直到生产者(SetThread)抢到CPU的资源:

    public void run() {
        while (true) {
            synchronized (s) {
              
                if(s.flag){//判断有没有“包子”,这时候是没有的,s.flag = false,执行下面的if语句
                    try {
                        s.wait(); //t1等着,释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //首先x = 0,先录入张三
                if (x % 2 == 0) {
                    s.name = "张三";
                    s.age = 23;
                } else {
                    s.name = "李四";
                    s.age = 24;
                }
                x++; //x=1
//这时候已经有“包子”了,就修改标志
                s.flag = true;
                //唤醒线程
                s.notify(); //唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。
            }
            //t1继续抢到执行权,或者t2抢到执行权
        }
    }

 

③若是t1继续抢到执行权:

1   synchronized (s) {
2               
3                 if(s.flag){//这个时候已经有了张三这个“包子”,而且flag = true;,所以进来
4                     try {
5                         s.wait(); //t1等待,并且释放锁,t1和t2抢占CPU资源,t1抢到继续等待,t2抢到就执行t2
6                     } catch (InterruptedException e) {
7                         e.printStackTrace();
8                     }
9                 }

 

④t2抢到执行权:

1     public void run() {
 2         while (true) { //true,进来
 3             synchronized (s) {
 4                 if(!s.flag){ //有“包子”,这时候的flag = true ,!s.flag = flase;不进来
 5                     try {
 6                         s.wait(); 
 7                     } catch (InterruptedException e) {
 8                         e.printStackTrace();
 9                     }
10                 }
11                 //消费“包子”
12                 System.out.println(s.name + "---" + s.age);
13                 
14                 //修改标记
15                 s.flag = false;
16                 //唤醒线程t1
17                 s.notify(); 
18             }
          
//唤醒t1,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。
19 } 
20 }

 

以上是关于java 22 - 17 多线程之等待唤醒机制(接16)的主要内容,如果未能解决你的问题,请参考以下文章

多线程进阶之等待唤醒机制

多线程等待唤醒机制之生产消费者模式

多线程等待唤醒机制之生产消费者模式

多线程间的通讯之等待唤醒机制

多线程的等待唤醒机制之消费者和生产者模式

Java多线程:阻塞队列与等待唤醒机制初探