首页 > 代码库 > java 22 - 17 多线程之等待唤醒机制(接16)

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     @Override11     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=131                 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                 //张三---2322                 //李四---2423                 24                 //修改标记25                 s.flag = false;26                 //唤醒线程27                 s.notify(); //唤醒t128             }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抢到就执行t26                     } 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                 //唤醒线程t117                 s.notify(); 18             }
          
//唤醒t1,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。
19 } 
20 }

 

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