Java多线程中的wait与notify
在
Java
多线程编程中,
wait()
的作用的是让当前线程进入阻塞状态,
notify()
是让当前线程唤醒继续执行。虽然是对线程状态的控制,但它们其实都是
Object
中的方法,这是因为
wait
与
notify
所起的作用与线程间的对象锁有关。
在执行
wait()
和
notify()
之前,必须要先获得对象锁
,即一定要和
synchronized
一起使用。
wait()
的含义是让出获得的对象锁,并让自己进入阻塞状态
。在
notify()
的时候也已经获得了对象锁,
所做的事情就是唤醒当前线程继续执行。
假如
synchronized
的锁对象是
obj
的话,
wait
和
notify
正确的使用方法是
obj.wait()
和
obj.notify()
。如果使用
this
作为锁,则可以直接写成
wait()
和
notify()
。
如果前后使用的锁对象不一致,会发生
IllegalMonitorStateException
。
当有多个线程共同使用一个对象锁时,
notify()
会随机选取一个执行过
wait()
的线程唤醒,其余会继续保持阻塞状态。如果想唤醒所有阻塞的进程,就使用到了
notifyAll()
。
案例:
采用
Java
多线程技术,设计实现一个符合生产者和消费者问题的程序。对一个对象(枪膛)进行操作,其最大容量是
6
颗子弹。生产者线程是一个压入线程,它不断向枪膛中压入子弹;消费者线程是一个射出线程,它不断从枪膛中射出子弹。
public
class
Test {
public
static
void
main(String[] args) {
Gun gun =
new
Gun();
Producter pro =
new
Producter(gun);
Consumer con =
new
Consumer(gun);
new
Thread(pro).start();
new
Thread(con).start();
}
}
//
枪
class
Gun {
private
int
maxBulletNum
= 6;
//
枪支最大子弹容量
private
int
residueBullet
= 0;
//
枪内剩余的子弹数
public
synchronized
void
pushBullet() {
//
压入子弹
if
(
residueBullet
==
maxBulletNum
) {
//
如果子弹满了,就等待
try
{
this
.wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
System.
out
.println(
"
压入了一个子弹,枪内剩余子弹:
"
+ ++
residueBullet
);
this
.notify();
//
唤醒等待的线程
}
public
synchronized
void
shoot() {
//
射击
if
(
residueBullet
== 0) {
//
没子弹了,就等待
try
{
this
.wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
System.
out
.println(
"
射击一次,枪内剩余子弹:
"
+ --
residueBullet
);
this
.notify();
//
唤醒等待的线程
}
}
//
消费者
class
Consumer
implements
Runnable {
private
Gun
gun
=
null
;
public
Consumer(Gun gun) {
this
.
gun
= gun;
}
public
void
run() {
while
(
true
) {
gun
.shoot();
try
{
Thread.
sleep
(2000);
}
catch
(InterruptedException e) {
//
TODO
Auto-generated catch block
e.printStackTrace();
}
}
}
}