1. java.lang.Object#wait()
Causes the current thread to wait until another thread invokes the{@link java.lang.Object#notify()} method or the {@link java.lang.Object#notifyAll()} method for this object.
In other words, this method behaves exactly as if it simply performs the call {@code wait(0)}. The current thread must own this object‘s monitor.
The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object‘s monitor to wake up either through a call to the {@code notify} method or the {@code notifyAll} method.
The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:
synchronized (obj) { while (condition does not hold) obj.wait(); ... // Perform action appropriate to condition }
This method should only be called by a thread that is the owner of this object‘s monitor. See the {@code notify} method for a description of the ways in which a thread can become the owner of a monitor.
2.
定义一个阻塞队列
import java.util.LinkedList; import java.util.Queue; import lombok.extern.slf4j.Slf4j; @Slf4j public class BlockingQueue<T> { private Queue<T> buffer = new LinkedList<>(); public T pop() throws InterruptedException { // 作用于当前对象 synchronized(this){ log.info("====>Thread {} 得到了锁", System.identityHashCode(Thread.currentThread())); while (buffer.isEmpty()){ this.wait(); } return buffer.remove(); } } public void push(T data){ synchronized (this){ buffer.add(data); notify(); } } }
测试
import java.util.concurrent.CountDownLatch; import lombok.extern.slf4j.Slf4j; @Slf4j public class BlockingQueueTest { public static void main(String[] args) throws InterruptedException { BlockingQueue<String> queue = new BlockingQueue<>(); CountDownLatch countDownLatch = new CountDownLatch(1); // 新建两个线程去队列中获取数据 Thread t1 = new Thread(()-> { try { countDownLatch.await(); String data = queue.pop(); log.info("====>t1 get data success! data:{}", data); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread t2 = new Thread(()-> { try { countDownLatch.await(); String data = queue.pop(); log.info("====>t2 get data success! data:{}", data); } catch (InterruptedException e) { e.printStackTrace(); } }); log.info("====>step1. t1_{}‘s state:{}", System.identityHashCode(t1), t1.getState()); log.info("====>step1. t2_{}‘s state:{}", System.identityHashCode(t2), t2.getState()); // 启动两个线程,使用 CountDownLatch 控制并发去抢占 push() 方法中的锁。 t1.setDaemon(true); t2.setDaemon(true); t1.start(); t2.start(); countDownLatch.countDown(); log.info("====>step2. t1_{}‘s state:{}", System.identityHashCode(t1), t1.getState()); log.info("====>step2. t2_{}‘s state:{}", System.identityHashCode(t2), t2.getState()); // 主线程等待10毫秒,获得锁的线程执行 wait() 方法后释放锁,Blocked 的线程得到了锁并执行了 wait() 方法后进入 waiting 状态。 Thread.sleep(10L); log.info("====>step3. t1_{}‘s state:{}", System.identityHashCode(t1), t1.getState()); log.info("====>step3. t2_{}‘s state:{}", System.identityHashCode(t2), t2.getState()); queue.push("哈哈哈"); // push() 方法调用 notify() 去唤醒 waiting 状态的线程,因为线程已经在 wait() 方法释放了 monitor 锁, // 线程被唤醒后会转到 blocked 状态重新去获取 monitor 锁,得到锁后状态变为 runnable 并执行之后的业务代码。 log.info("====>step4. t1_{}‘s state:{}", System.identityHashCode(t1), t1.getState()); log.info("====>step4. t2_{}‘s state:{}", System.identityHashCode(t2), t2.getState()); // 主线程等待10毫秒 Thread.sleep(10L); log.info("====>step5. t1_{}‘s state:{}", System.identityHashCode(t1), t1.getState()); log.info("====>step6. t2_{}‘s state:{}", System.identityHashCode(t2), t2.getState()); // java虚拟机(相当于进程)退出的时机是:虚拟机中所有存活的线程都是守护线程。只要还有存活的非守护线程虚拟机就不会退出, // 而是等待非守护线程执行完毕;反之,如果虚拟机中的线程都是守护线程,那么不管这些线程的死活java虚拟机都会退出。 Thread.sleep(1000L); log.info("====>main thread‘s state:{}", Thread.currentThread().getState()); } }
运行结果:

Java并发编程--wait/notify/notifyAll 方法的使用
原文:https://www.cnblogs.com/xxoome/p/13283463.html