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

 更新时间:2021年09月27日 10:26:17   作者:百了江  
这篇文章主要介绍了Object类中的wait()和notify()方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

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变成负数也是有可能的(两个消费者进程先进来都堵塞).

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

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

相关文章

  • 图解Java ReentrantLock的条件变量Condition机制

    图解Java ReentrantLock的条件变量Condition机制

    想必大家都使用过wait()和notify()这两个方法把,他们主要用于多线程间的协同处理。而RenentrantLock也支持这样条件变量的能力,而且相对于synchronized 更加强大,能够支持多个条件变量,本文就来详细说说
    2022-10-10
  • IDEA+Maven搭建Spring环境的详细教程

    IDEA+Maven搭建Spring环境的详细教程

    这篇文章主要介绍了IDEA+Maven搭建Spring环境的详细教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • Spring Aware标记接口使用案例解析

    Spring Aware标记接口使用案例解析

    这篇文章主要介绍了Spring Aware标记接口使用案例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • C# log4net使用案例详解

    C# log4net使用案例详解

    这篇文章主要介绍了C# log4net使用案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • java中Ajax与Axios的使用小结

    java中Ajax与Axios的使用小结

    在项目中我们经常会遇到需要向请求头中添加消息的场景,本文主要介绍了java中Ajax与Axios的使用小结,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2024-02-02
  • Java获取Excel中图片所在的行和列坐标位置

    Java获取Excel中图片所在的行和列坐标位置

    这篇文章主要介绍了Java获取Excel中图片所在的行和列坐标位置,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-08-08
  • Spring WebFlux的使用指南

    Spring WebFlux的使用指南

    这篇文章主要介绍了Spring WebFlux的使用指南,帮助大家更好的理解和学习使用Spring框架,感兴趣的朋友可以了解下
    2021-05-05
  • java反射拼接方法名动态执行方法实例

    java反射拼接方法名动态执行方法实例

    下面小编就为大家带来一篇java反射拼接方法名动态执行方法实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-08-08
  • 解决微服务feign调用添加token的问题

    解决微服务feign调用添加token的问题

    这篇文章主要介绍了解决微服务feign调用添加token的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • 学习SpringMVC——如何获取请求参数详解

    学习SpringMVC——如何获取请求参数详解

    本篇文章主要介绍了SpringMVC——如何获取请求参数详解,详细的介绍了每种参数注解的用法。具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2016-12-12

最新评论