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 }
时间: 2024-12-06 07:21:38

java 22 - 17 多线程之等待唤醒机制(接16)的相关文章

java基础知识回顾之java Thread类学习(八)--java多线程通信等待唤醒机制经典应用(生产者消费者)

 *java多线程--等待唤醒机制:经典的体现"生产者和消费者模型 *对于此模型,应该明确以下几点: *1.生产者仅仅在仓库未满的时候生产,仓库满了则停止生产. *2.消费者仅仅在有产品的时候才能消费,仓空则等待. *3.当消费者发现仓储没有产品可消费的时候,会唤醒等待生产者生产. *4.生产者在生产出可以消费的产品的时候,应该通知等待的消费者去消费. 下面先介绍个简单的生产者消费者例子:本例只适用于两个线程,一个线程生产,一个线程负责消费. 生产一个资源,就得消费一个资源. 代码如下: pub

java基础知识回顾之java Thread类学习(七)--java多线程通信等待唤醒机制(wait和notify,notifyAll)

1.wait和notify,notifyAll: wait和notify,notifyAll是Object类方法,因为等待和唤醒必须是同一个锁,不可以对不同锁中的线程进行唤醒,而锁可以是任意对象,所以可以被任意对象调用的方法,定义在Object基类中. wait()方法:对此对象调用wait方法导致本线程放弃对象锁,让线程处于冻结状态,进入等待线程的线程池当中.wait是指已经进入同步锁的线程,让自己暂时让出同步锁,以便使其他正在等待此锁的线程可以进入同步锁并运行,只有其它线程调用notify方

java多线程的等待唤醒机制及如何解决同步过程中的安全问题

/* class Person{ String name; String sex; boolean flag = true; public void setPerson(String name, String sex){ this.sex=sex; this.name=name; } } class Input implements Runnable{ int x=0; Person p; Input(Person p){ this.p=p; } public void run(){ while

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

/** * 等待唤醒之生产者和消费者模型 * 生成者: 创建和添加数据的线程 * 消费者: 销毁和删除数据的线程 * 问题1: 生成者生成数据过快, 消费者消费数据相对慢,不接收数据了, 会造成数据丢失 * 问题2: 消费者消费数据过快, 生成者生成数据相对慢,不发送数据了, 会造成数据被重复读取 * 总结 : 生产数据过快会造成数据丢失 * 生成数据过慢会造成数据被重复读取 * * * wait()和notifyAll()用法: * 1. 必须是同一个对象的wait()和和notifyAll(

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

上篇楼主说明了多线程中死锁产生的原因并抛出问题--死锁的解放方案,那么在本篇文章,楼主将引用一个KFC生产汉堡,顾客购买汉堡的过程来说明死锁解决方案及多线程的等待唤醒机制. 简单地用一幅图来说明KFC生产汉堡,顾客来消费的过程: 场景分析: 资源类:Hamburger 设置汉堡数据:SetThread(生产者) 获取汉堡数据:GetThread(消费者) 测试类:HamburgerTest 不同种类的线程(生产者.消费者)针对同一资源(汉堡)的操作 当汉堡有存货的时候,汉堡师傅不再生产,顾客可消

Java---18---多线程:等待唤醒机制

class Res { String name; String sex; } class Input implements Runnable { private Res r; public Input(Res r) { // TODO Auto-generated constructor stub this.r = r; } public void run() { int x = 0; while (true) { synchronized (r) { if (x == 0) { r.name

java多线程中的生产者与消费者之等待唤醒机制@Version1.0

一.生产者消费者模式的学生类成员变量生产与消费demo,第一版1.等待唤醒:    Object类中提供了三个方法:    wait():等待    notify():唤醒单个线程    notifyAll():唤醒所有线程2.为什么这些方法不定义在Thread类中呢?  这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象.  所以,这些方法必须定义在Object类中.3.当我们在使用多线程的时候有的时候需要,一条线程产生一个数据,另一条线程接着消费一个数据,一边生产一边消费,

JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制

JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是class对象 我们在上节验证了同步函数的锁是this,但是对于静态同步函数,你又知道多少呢? 我们做一个这样的小实验,我们给show方法加上static关键字去修饰 private static synchronized void show() { if (tick > 0) { try { Thread

java多线程(死锁,lock接口,等待唤醒机制)

一.Lock接口 常用方法 Lock提供了一个更加面对对象的锁,在该锁中提供了更多的操作锁的功能. 使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,对电影院卖票案例中Ticket类进行如下代码修改: public class Ticket implements Runnable { //共100票 int ticket = 100; //创建Lock锁对象 Lock ck = new ReentrantLock(); @Override public void run