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 }
何事都只需坚持..
难?
维熟尔。
LZL的自学历程...只需坚持