聊聊Object类中的wait()和notify()方法

目录
  • Object类中的wait()和notify()方法
    • 一、特点
    • 二、wait()方法的作用
    • 三、notify()方法的作用
    • 四、wait()和notify()的使用
  • object中的wait和notify细节
    • wait
    • jdk中为啥要规定我们要使用while,而不是if?

Object类中的wait()和notify()方法

一、特点

wait()和notify()方法并不是线程对象的方法,是Java中任何一个Java对象都有的方法,并不特殊。

二、wait()方法的作用

Object obj = new Object();
obj.wait();

表示:obj.wait();方法的调用,会让“当前线程(正在obj对象上活动的线程)”进入等待状态。

三、notify()方法的作用

Object obj = new Object();
obj.notify();

表示:唤醒正在obj对象上等待的线程。

补充:

Object obj = new Object();
obj.notifyAll();

表示:唤醒正在obj对象上等待的所有线程。

四、wait()和notify()的使用

wait()和notify()方法都是建立在synchronized线程同步的基础之上

重点

obj.wait()方法会让正在obj对象上活动的当前线程进入等待状态,并且释放之前占有的obj对象的锁。

obj.notify()方法只会通知,不会释放之前占有的obj对象的锁。

object中的wait和notify细节

wait

jdk源码:

重点看下划线的地方,是不是有些不理解。有个印象我们继续往下看。

public class resourse {
    private Integer number = 0 ;
    /**
     * 用if为啥不行
     * 1:首先一点我们要搞清楚 wait操作会释放锁
     * 2:想想这种情况,当一个生产者线程执行的时候 if number!=0 (此时的number为1 ) 就会发生阻塞 这时候
     * 释放出锁 这时候又一个生产者进程进来又会被wait住.然后一个生产者进程进来,消费了一个 但是notifyall 将所有的进程
     * 都解开了 。。那两个生产者进程就会直接运行if后面的东西并没有被拉回来重新判断一下。这样就造成了number的值变成2.同理number
     * 变成负数也是有可能的(两个消费者进程先进来都堵塞).
     *
     *
     *
     *
     * @throws Exception
     */
    public synchronized void  produce () throws Exception
    {
//        判断  这里用while 用if多与两个线程容易出错
//        不等于0就要等待消费者消费完
         if(number!=0)
         {
             this.wait();
         }
//         干活
        number++;
        System.out.println(Thread.currentThread().getName() + "的资源数为:" + number.toString());
//        释放
        this.notifyAll();
    }
//wait操作会释放锁
    public synchronized void consumer () throws Exception
    {
        //    等于零就要等待生产者生产
        if (number == 0)
        {
            this.wait();
        }
//        消费
        number--;
        System.out.println(Thread.currentThread().getName() + "的资源数为:" + number.toString());
//        释放
        this.notifyAll();
    }
}

调用者。这里开启了两个生产者和两个消费者线程。生产者线程都执行100次的produce,消费者线程都执行100次的consumer

public class main {
    public static void main (String[] args) {
        resourse resourse = new resourse();
            new Thread(()->{
                try{
                    for (int i=0 ; i<100;i++)
                    resourse.produce();
                }catch (Exception e)
                {
                    e.printStackTrace();
                }
            }).start();
        new Thread(()->{
            try{
                for (int i=0 ; i<100;i++)
                resourse.produce();
            }catch (Exception e)
            {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try{
                for (int i=0 ; i<100;i++)
                    resourse.consumer();
            }catch (Exception e)
            {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try{
                for (int i=0 ; i<100;i++)
                resourse.consumer();
            }catch (Exception e)
            {
                e.printStackTrace();
            }
        }).start();
    }
}

我要说的重点是:

这样设计真的合理吗?

jdk中为啥要规定我们要使用while,而不是if?

用if为啥不行

1:首先一点我们要搞清楚 wait操作会释放锁

2:想想这种情况,当一个生产者线程执行的时候 if number!=0 (此时的number为1 ) 就会发生阻塞 这时候释放出锁 这时候又一个生产者进程进来又会被wait住.然后一个生产者进程进来,消费了一个 但是notifyall 将所有的进程都解开了 。。那两个生产者进程就会直接运行if后面的东西并没有被拉回来重新判断一下。这样就造成了number的值变成2.同理number变成负数也是有可能的(两个消费者进程先进来都堵塞).

这个问题绝对是干货,在工作中绝对会遇到生产者消费者问题,不少程序员会在这个地方踩坑。面试的时候如果考到你这个地方,你能解答出深层原理来。相信面试官会高看你一眼。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 详细分析java线程wait和notify

    wait()和notify()是直接隶属于Object类,也就是说,所有对象都拥有这一对方法.初看起来这十分 不可思议,但是实际上却是很自然的,因为这一对方法阻塞时要释放占用的锁,而锁是任何对象都具有的,调用任意对象的 wait() 方法导致线程阻塞,并且该对象上的锁被释放.而调用任意对象的notify()方法则导致因调用该对象的wait() 方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行). 其次,wait()和notify()可在任何位置调用,但是这一对方法却必须在

  • java Object wait方法详细介绍

    java Object wait方法 当线程B访问某个共享资源时,想获取资源的锁对象,发现这个锁已经被线程A拿到了,这个时候,线程B只能被挂起,等待线程A释放锁. 但是拿到锁的线程A在执行的过程中,因为某些条件还不满足,暂时不想继续执行下去,想先等待一下(注意:是已经拿到锁的线程A自己想主动等待的),希望等到某个条件满足后,继续执行任务.在同步代码块里,线程A必须先释放锁,线程B才有资格获取锁,进入同步代码块,执行代码.等线程B执行完后,线程A需要的条件已经满足,那么这个时候必须有一个通知机制,

  • java多线程之wait(),notify(),notifyAll()的详解分析

    wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每个对象都有wait(),notify(),notifyAll()的功能.因为每个对象都有锁,锁是每个对象的基础,当然操作锁的方法也是最基础了. wait导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或被其他线程中断.wait只能由持有对像锁的线程来调用. notify唤醒在此对象监视器上等待的单个线程.如果所有线程都在此对象上等

  • Object类wait及notify方法原理实例解析

    Object类中的wait和notify方法(生产者和消费者模式) 不是通过线程调用 wait(): 让正在当前对象上活动的线程进入等待状态,无期限等待,直到被唤醒为止 notify(): 让正在当前对象上等待的线程唤醒 notifyAll(): 唤醒当前对象上处于等待的所有线程 生产者和消费者模式 生产线程和消费线程达到均衡 wait方法和notify方法建立在synchronized线程同步的基础之上 wait方法: 释放当前对象占有的锁 notify方法: 通知,不会释放锁 实现生产者和消

  • 聊聊Object类中的wait()和notify()方法

    目录 Object类中的wait()和notify()方法 一.特点 二.wait()方法的作用 三.notify()方法的作用 四.wait()和notify()的使用 object中的wait和notify细节 wait jdk中为啥要规定我们要使用while,而不是if? Object类中的wait()和notify()方法 一.特点 wait()和notify()方法并不是线程对象的方法,是Java中任何一个Java对象都有的方法,并不特殊. 二.wait()方法的作用 Object o

  • 详谈Java中Object类中的方法以及finalize函数作用

    Object是所有类的父类,任何类都默认继承Object. 一.Object类中的方法 1.clone方法 保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常. 主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用传递,我们有时候不希望在方法里讲参数改变,这是就需要在类中复写clone方法. 2.getClass方法 final方法,获得运行时类型. 3.toString方法 该方法

  • Python object类中的特殊方法代码讲解

    python版本:3.8 class object: """ The most base type """ # del obj.xxx或delattr(obj,'xxx')时被调用,删除对象中的一个属性 def __delattr__(self, *args, **kwargs): # real signature unknown """ Implement delattr(self, name). "&q

  • IOS中自定义类中限制使用原生实例化方法

    IOS中自定义类中限制使用原生实例化方法 在自定义的类中,除了有系统自带的实例化方法外,还可能会有开发者自定义的实例化方法.当不想使用系统自定义方法时,而仅使用自定义的实例化方法时,可以这样做下限制. 如下示例所示: #import <UIKit/UIKit.h> @interface MYView : UIView // 限制使用系统方法进行实例化 // 方法1 - (instancetype)init UNAVAILABLE_ATTRIBUTE; // 方法2 - (instancetyp

  • python访问类中docstring注释的实现方法

    本文实例讲述了python访问类中docstring注释的实现方法.分享给大家供大家参考.具体分析如下: python的类注释是可以通过代码访问的,这样非常利于书写说明文档 class Foo: pass class Bar: """Representation of a Bar""" pass assert Foo.__doc__ == None assert Bar.__doc__ == "Representation of a B

  • 一篇文章带你了解java Object根类中关于toString,equals的方法

    目录 toString: 代码案例: equals: 代码案例: 总结 toString: 概念:拼接对象的地址值:toString()方法用于返回表示对象值的字符串(返回的是String对象). 快捷写法:Alt+Insert,直接会显示toString的方法,选取需要返回的对象就行. 代码案例: 定义一个person类,属性如下: (1)身份证号,性别,姓名,年龄,户籍,出生日期(Data类型,需要引用java.uitl.Data)功能: (2)自我介绍:介绍格式:(toString) 身份

  • C++实践Time类中的运算符重载参考方法

    [项目-Time类中的运算符重载] 实现Time类中的运算符重载. class CTime { private: unsigned short int hour; // 时 unsigned short int minute; // 分 unsigned short int second; // 秒 public: CTime(int h=0,int m=0,int s=0); void setTime(int h,int m,int s); void display(); //二目的比较运算符

  • 你了解Java中的Object类吗

    任何一个类默认继承Object类,就算没有直接继承,最终也会间接继承. Object类,有两种方式找到: 第一种:在源码当中找到 第二种:查阅java类库的帮助文档 Object类中两个重要的方法: boolean equals (Object obj) //判断两个对象是否相等 String toString () //将对象转换成字符串形式 equals方法: 源代码: public boolean equals(Object obj) { return (this == obj); } 作

  • Java Object类和包装类深入解读

    目录 查看源代码方法 Object类 定义及应用 1. toString() 2. equals( ) 包装类 定义及应用 装箱和拆箱 自己实现包装类 通过包装类让Object类接收基本数据类型 包装类的对象比较 包装类和String的相互转换 查看源代码方法 在IDEA中双击 shift 键,可以搜索相关类名,查看源代码 点击Structure ,左侧用橙色床框住的部分是类的结构,结构包含所有的方法.属性.内部类的声明.结构中带绿色小锁的图标表示 public 权限,钥匙图标就是继承权限(pr

随机推荐