java 线程中wait和notify的问题
发布网友
发布时间:2022-05-01 20:48
我来回答
共1个回答
热心网友
时间:2022-06-23 04:00
这个程序挺经典的.
我不知道你对wait这是不是很熟,我按我的说,有问题再沟通:
首先看
main函数,两句话,Procer对象和Consumer对象都引用了同一个p.
Procer类的run
前面有
synchronized(p)
说明该线程用到 synchronized 里的对象变量时,别的线程只能等待.
再看
if(p.bFull) {
try{p.wait();} catch (Exception e) {}
}
也就是说该线程用到了p对象,
而如果当运行到该线程时,
且p.bFull为真时
该线程进行等待,让其他线程运行
到这的思路如果没有问题,
那么我们假设
假设
p.bFull为假,
那么会再往下运行
也就是设置姓名,性别,
此时p.bFull仍然为假
之后设置 p.bFull 为真
p.notify()
当设置p.bFull为真时,表示下次如果仍然是该线程执行,将会wait.
而p.notify()是为了解以p为锁的线程,因为当前线程正在运行,所以当前线程肯定不需要解锁,那可能需要被解锁的,也就是Consumer对象的线程.
当前线程从开始运行到目前的位置,Consumer线程是一直在wait的,因为Consumer线程在while下面直接就synchronized (p)也就是这两个线程同时只能一个线程运行.
也就是说,要么这次运行Procer,要么运行Consumer
按我上面说的,Procer的运行逻辑应该已经清楚了,而Consumer的线程运行逻辑跟Procer一样,我就不多说了,
问题的关键在于
当Procer运行一次,之后Consumer运行一次,是比较好理解,交叉运行呗.
但如果Procer运行完,又运行了Procer线程,而没有让Consumer运行的时候,程序会怎么运行?(反之一样)
我下面来解释.
当Procer运行一次,又运行了Procer时,这时因为没有Consumer线程的介入
,p的bFull应该为真,
这时运行到
Procer线程的
if (p.bFull) {
try {
p.wait();
} catch (Exception e) {
}
时,因为p.bFull为真了,
所以运行下面的代码,
也就是让当前线程等待,而用来等待的锁就是p
这时,当前线程等待了,
也就要执行Consumer线程了,也就是相当于强制切换线程
运行一次Consumer线程后,Procer仍然在等待,如果这样,那就会仍然运行Consumer线程,根据逻辑,Consumer会像Procer一样,由于
if(!p.bFull) {
try{p.wait(); } catch (Exception e) {} }
而等待
这样两个线程都等待了
(如果你问,当!p.bFull如果成立,那p.bFull就不成立,那Procer不是该运行了吗?但是,我刚刚的假设是当Procer已经等待时,那么Procer就不会因为p.bFull的改变而继续运行了)
按上面所说,如果按这样的逻辑,最终会导致两个线程同时等待没有解锁,
为了解决这个问题,
就在程序的每个线程的
p.bFull = false;
后面,加上了
p.notify();
让以p为锁的线程解锁等待.
这样,就可以使程序的两个线程来回切换了.