Thread之wait()&notify()

问题:假想在服务器上运行着若干个响应客户端请求的线程,这些线程需要连接到同一数据库,但任一时刻只能获得一定数目的数据库连接。你要怎样才能够将这些固定数量的数据库连接分配给大量的线程?

一种控制访问特定资源的方法,就是使用信号量计数. 我们可以将一个信号量初始化为可获得的数据库连接个数。一旦某个线程获得了信号量,可获得的数据库连接数减一。线程消耗完资源并释放该资源时,计数器就会加一。当信号量控制的所有资源都已被占用时,若有线程试图访问此信号量,则会进入阻塞状态,直到有可用资源被释放.

信号量最常见的用法是解决“消费者-生产者问题”。当一个线程进行工作时,若另外一个线程访问同一共享变量,就可能产生此问题。消费者线程只能在生产者线程完成生产后才能够访问数据。使用信号量来解决这个问题,就需要创建一个初始化为零的信号量,从而让消费者线程访问此信号量时发生阻塞。每当完成单位工作时,生产者线程就会向该信号量发信号(释放资源)。每当消费者线程消费了单位生产结果并需要新的数据单元时,它就会试图再次获取信号量。因此信号量的值就总是等于生产完毕可供消费的数据单元数。这种方法比采用消费者线程不停检查是否有可用数据单元的方法要高效得多。因为消费者线程醒来后,倘若没有找到可用的数据单元,就会再度进入睡眠状态,这样的操作系统开销是非常昂贵的。

举一个简单的例子:
假设有两个线程,彼此需要通信。再假设线程A正在等线程B的消息:

// Thread A
public void waitForMessage() {
while (hasMessage == false) {
Thread.sleep(100);
}
}
// Thread B
public void setMessage(String message) {
...
hasMessage = true;
}



这样写可以,但比较糟糕。线程A需要每100ms检测一次(一秒检测10次)线程B是否发送了消息;它也可能睡过了头(指Thread.sleep(100)——译者),没能及时接收消息。还有,如果多个线程都在等待消息,应该怎么办?难道没有一种方式可以让线程A不用这么呆头呆脑的等线程B的消息吗?
幸运的是,wait() 和 notify()方法能做到。
Wait()方法用在同步的代码块里,当wait()被执行时,锁会被释放,线程进入等待状态。
方法notify() 同样用在同步的代码块里。Notify()将通知等待相同锁的线程,如果有多个线程在等待这个锁,将从中随机选择一个进行通知。

下面是更新的代码:

// Thread A
public synchronized void waitForMessage() {
try {
wait();
}
catch (InterruptedException ex) { }
}

// Thread B
public synchronized void setMessage(String message) {
...
notify();
}

线程B调用notify(),并离开这个同步方法后(释放加在this上的锁), 线程A 重新获得这个锁,并完成它的同步代码。本例中,它只是返回。
你也可以选择等待的最大时间值,wait()方法可以将其作为参数:
wait(100);
如果线程从未被通知,这种写法等价于让线程sleep一个指定时间;不幸的是,我们没法知道wait()方法的返回是由于等待的时间到了,还是由于线程被通知。
另一种通知的方法, notifyAll(), 将会通知所有等待这个锁的线程,而不是只通知一个。
方法 wait(), notify(), 和 notifyAll() 是Object 类的方法,因此所有的Java对象都会有这些方法,就像所有的Java对象都可用作一个锁一样。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值