# wait()、notify()、notifyAll()的使用你也不能忘了阿
# 线程的状态
# Java提供的管程方法
Java提供的管程方法必须在synchronized里面使用.
# wait()
wait()会让调用线程释放持有的锁, 并进入阻塞状态, 等待被唤醒.
Java提供了几种wait的重载方法, 具体如下
| method | desc |
|---|---|
| void wait() | Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. |
| void wait(long timeout) | Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed. |
| void wait(long timeout, int nanos) | Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed. |
设置时间的wait方法, 区别在于如果没有被notify或notifyAll唤醒, 也会自动被唤醒.
注意: wait(0)与wait()等效.
# notify()和notifyAll()
两者的释义如下:
| method | desc |
|---|---|
| void notify() | Wakes up a single thread that is waiting on this object's monitor. |
| void notifyAll() | Wakes up all threads that are waiting on this object's monitor. |
两者的区别在于: notifyAll()是唤醒所有
# sleep()
线程进入
Blocked状态, 不释放持有的锁, 但会释放CPU资源, 等待设置的时间结束, 则会进入Runnable状态.不需要在synchronized中调用, 不属于管程的方法
# 等待通知机制的应用场景
# 实现简单的等待通知机制
public class WaitTest {
//实例方法加锁
public synchronized void waiting(){
try {
this.wait(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void notifyIt(){
this.notifyAll();
}
static class task implements Runnable{
private WaitTest test;
private AtomicInteger count;
public task(WaitTest test, AtomicInteger count){
this.test = test;
this.count = count;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
//累加count, 并输出结果到控制台
System.out.println("count curr is "+ count.incrementAndGet());
//每次累加都调用notifyAll()通知所有对象锁等待队列中的线程
//notifyAll()放的位置不一样,会造成不同的效果,放for外面则累加完才通知等待队列中的线程
test.notifyIt();
}
}
}
public static void main(String[] args) {
WaitTest test = new WaitTest();
//计数器count
AtomicInteger count = new AtomicInteger(0);
//启动一个线程任务-累加count100次
new Thread(new task(test, count)).start();
//while判断count是否>=100, 否则就一直调用wait()
while(count.get() < 100){
System.out.println("main thread waiting start");
test.waiting();
System.out.println("main thread waiting end");
}
System.out.println("code executed, count = "+count.get());
}
}
# 实现生产者消费者
较为常见的场景是
生产者消费者, 常见的是场景, 实现方式却不常用, 由于众多中间件及其他即开即用方案的流行, 早已不再自己造轮子去实现此方案了. 虽然不常用, 但场景是基础且经典的, 我们依然必须了解和掌握.经常有一类业务需求说要
当某某情况时, 做某某操作, 不满足条件时就等条件满足再做, 接到这个需求时, 第一时间可能想, 那就每隔一段时间轮询是否满足条件即可, 但细想就会发现, 其实这样时效性不好保障, 也很浪费资源.其实这种业务模型就是
生产者&消费者, 当条件满足时就通知消费者进行消费, 当没有消费内容时, 就等待, 直到生产者将其唤醒. 接下来我们利用wait()和notify()实现一个生产者消费者模式
public class ProducerAndConsumer {
//公用队列
private final ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();
//实例对象锁-生产者和消费者共同持有一把锁
private final Object lock = new Object();
//业务生产者的实现-此处抽象为生产随机数
private final static Random r = new Random();
private Producer createProducer(){
return new Producer();
}
private Consumer createConsumer(){
return new Consumer();
}
class Producer{
//生产内容-不断构造生产的内容并放入公用队列中
public void producer() throws InterruptedException {
int count = 0;
while (true){
queue.add(r.nextInt(100));
count++;
//当有放入内容时, 立即通知消费者进行消费
synchronized (lock){
lock.notifyAll();
}
//无关内容
if(count%10==0){
TimeUnit.MILLISECONDS.sleep(5000);
}
if(count > 1000) break;
}
}
}
class Consumer{
public void consumer() throws InterruptedException {
//消费者一直while(true)进行消费
while(true){
//如果queue中没有内容则将线程变为WAITING状态
if(queue.isEmpty()){
synchronized (lock){
lock.wait();
}
}else{
//消费queue中的内容
System.out.println("消费了"+queue.poll());
TimeUnit.MILLISECONDS.sleep(1000);
}
}
}
}
public static void main(String[] args) {
ProducerAndConsumer test = new ProducerAndConsumer();
Producer producer = test.createProducer();
Consumer consumer = test.createConsumer();
//异步启动生产者
new Thread(()->{
try {
producer.producer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
//异步启动消费者
new Thread(()->{
try {
consumer.consumer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
//检查queue中任务的数量
new Thread(()->{
try {
while (true){
System.out.println("queue size = "+test.queue.size());
TimeUnit.SECONDS.sleep(2);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
# 简析wait()和notify()原理
# 参考
https://www.cnblogs.com/paddix/p/5381958.html