深度理解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
变成负数也是有可能的(两个消费者进程先进来都堵塞).
这个问题绝对是干货,在工作中绝对会遇到生产者消费者问题,不少程序员会在这个地方踩坑。面试的时候如果考到你这个地方,你能解答出深层原理来。相信面试官会高看你一眼。