Java中的sleep() | wait() | notify() | notifyAll()
来源:互联网 发布:淘宝王子团队怎么联系 编辑:程序博客网 时间:2024/05/22 02:23
sleep()方法
首先,看 源代码 和 Javadoc
/** * Causes the currently executing thread to sleep (temporarily cease * execution) for the specified number of milliseconds, subject to * the precision and accuracy of system timers and schedulers. The thread * does not lose ownership of any monitors. * * @param millis * the length of time to sleep in milliseconds * * @throws IllegalArgumentException * if the value of {@code millis} is negative * * @throws InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when this exception is thrown. */public static native void sleep(long millis) throws InterruptedException;
可以看出这是调用的本地方法,所以在这里看不到具体的细节了,所以我们就来看一下Javadoc怎么说吧。
首先看第一句:
Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds将导致当前线程在指定的毫秒时间段沉睡,并暂时释放CPU时间片
而后面又提到:
The thread does not lose ownership of any monitors线程将不会释放任何已获得的锁 (这里的monitor指的就是我们平时所说的锁)
可以看出,sleep()方法只会使线程沉睡一段时间,但是如果线程在这之前已经获得了锁,那么这些锁将不会因为sleep()方法的调用而被释放。
参考以下场景:
Object object = new Object;synchronized (object) { try { Thread.sleep(1000); } catch (InterruptedException e) { // do something... }}
这时,对象object作为锁被当前线程获得,调用sleep()方法并不会释放锁
再来看对于异常信息的描述:
@throws InterruptedException if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.如果任何其它线程在当前线程執行sleep()方法时中断了当前线程,则会抛出InterruptedException(中断异常),并且当前线程的‘中断状态’将在异常抛出之后被清除(复位)。
可以看出,sleep()方法在执行时是可以被其它线程中断的,所以在调用sleep()方法时,需要对InterruptedException做出必要的处理来响应中断状态。
wait() notify() 和 notifyAll()
上面介绍了sleep()方法,现在再来看wait() notify() 和 notifyAll()方法。
wait() notify() 和 notifyAll() 是Object类中的final类型方法,不可以被子类Override。由于Object类是所有类的父类,所以所有类和它们的实例都将拥有这三个方法。
public final native void wait(long timeout) throws InterruptedException;public final void wait() throws InterruptedException { wait(0);}public final native void notify();public final native void notifyAll();
可以看出它们也都是本地方法,查看Javadoc,将这三个方法总结一下:
wait() notify()和notifyAll()的使用有个共同的前提条件,就是当前线程必须获得 这三个方法所属实例 的锁(monitor)。也就是说,它们的调用必须在同步块的内部,不然就会抛出 IllegalMonitorStateException。
参考下面的代码:
Object object = new Object();synchronized (object) { try { object.wait(); } catch (InterruptedException e) { // do something... } // object.notify(); object.notifyAll();}
而如下这样的调用则是错误的,将会抛出 IllegalMonitorStateException,因为当前线程并没有获得objectB的锁(monitor):
Object objectA = new Object();Object objectB = new Object();synchronized (objectA) { try { objectB.wait(); } catch (InterruptedException e) { // do something... } // object.notify(); objectB.notifyAll();}
当一个线程调用了wait()或wait(0),它将进入WAITING状态,如果调用wait(timeout)则将进入TIMED_WAITING状态。
当一个线程进入了某个锁(monitor)的wait()方法后,将释放这个锁,并且线程退出wait()方法有以下三种情况:
1. 中断
2. 对于当前调用wait()方法的锁(monitor)对象objectA,其它线程获得了这个锁objectA,并且调用objectA的notify()或notifyAll()方法
3. 超时(当且仅当当前状态是TIMED_WAITING,如果是WAITING,则将等待直到条件1或2出现,否则将成为死锁)
对于某个锁(monitor)对象的notify()或notifyAll()方法,它们都是用于通知持有此锁并调用了wait()方法的线程,从WAITING状态唤醒。
notify()方法是在等待队列的所有线程中随机选择一个进行通知,而notifyAll()则是通知所有等待的线程。
下面用文字描述一个例子:
对于某个对象lock,当一个线程A获得lock的锁(monitor),并调用lock.wait(),线程B随后获得lock的锁(monitor),也调用lock.wait()。此时,线程A和B都处于WAITING状态,并且lock的锁已经被释放。线程C随后获得lock的锁(monitor),并调用lock.notify(),并在退出lock的同步块之前做了某操作M。随后,系统将在A和B中随机选择一个出来,并将其唤醒。如果线程C获得锁之后调用了lock.notifyAll(),那么随后线程A和B将同时被唤醒。这里值得注意的是,当线程C调用了notify()或notifyAll()后,线程A或B不会立刻被唤醒,而是等待线程C的后续操作M完毕,并退出lock的同步块,释放了lock的锁(monitor)之后,线程A或B才能重新获得lock的锁(monitor),并被唤醒。
举例子
为了让后面的代码尽量的简洁,先写出几个公共方法:
/** * 线程休眠,并对中断异常{@link InterruptedException}仅作控制台输出处理 * * @param millis 休眠时长(毫秒) */public static void sleepIgnoreInterrupt(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); }}/** * 为一个指定的线程创建一个监控线程,尽力按顺序采集线程所经历的每一个{@link Thread.State} * * @param thread 被监控的线程 */public static void startThreadStateDetector(Thread thread) { Thread stateDetector = new Thread(new Runnable() { @Override public void run() { LinkedHashSet<String> states = new LinkedHashSet<>(); while (thread.getState() != Thread.State.TERMINATED) states.add(thread.getState().name()); states.add(thread.getState().name()); System.out.println(String.format("Thread-[%s], States %s", thread.getName(), states)); ); stateDetector.start(); // 等待监控线程完全启动 sleepIgnoreInterrupt(300);}/** * 打印带有线程名称的日志 * * @param message 日志内容 */public static void printMsgWithThreadName(String message) { System.out.println("Thread-[" + Thread.currentThread().getName() + "] " + message);}
1. 首先举一个关于wait()和notify()的简单例子:
public static void printSimpleWaitAndNotify() { Object lock = new Object(); Thread threadJimmy = new Thread(new Runnable() { @Override public void run() { synchronized (lock) { try { printMsgWithThreadName("Ready to invoke wait()..."); lock.wait(); printMsgWithThreadName("Exit wait()..."); } catch (InterruptedException e) { // do something... } } } }, "ThreadJimmy"); Thread threadLouis = new Thread(new Runnable() { @Override public void run() { synchronized (lock) { printMsgWithThreadName("Ready to invoke notify()..."); lock.notify(); printMsgWithThreadName("Exit notify()..."); } } }, "ThreadLouis"); // 监控线程的状态变化 startThreadStateDetector(threadJimmy); startThreadStateDetector(threadLouis); threadJimmy.start(); // 等待线程threadJimmy调用wait()方法并释放锁 sleepIgnoreInterrupt(1000); threadLouis.start();}
运行结果为:
Thread-[ThreadJimmy] Ready to invoke wait()...Thread-[ThreadLouis] Ready to invoke notify()...Thread-[ThreadLouis] Exit notify()...Thread-[ThreadJimmy] Exit wait()...Thread-[ThreadJimmy], States [NEW, RUNNABLE, WAITING, BLOCKED, TERMINATED]Thread-[ThreadLouis], States [NEW, RUNNABLE, TERMINATED]
从运行结果可以清晰的看到,ThreadJimmy获得lock的锁(monitor)并调用wait()方法,随后释放了lock的锁(monitor),随后ThreadLouis获得lock的锁(monitor)并调用notify()方法,释放lock的锁(monitor),随后ThreadJimmy重新获得lock的锁(monitor),并退出wait()方法。
从线程的States监控日志中可以看出,ThreadJimmy在WAITING状态之后进入了BLOCKED状态,表明ThreadLouis在调用notify()之后,释放lock的锁(monitor)之前的这段时间里ThreadJimmy是被阻塞了的。
2. 再来个稍微复杂一点的例子:
private static void printComplexWaitAndNotify() { Object lock = new Object(); Thread consumerLouis = new Thread(new Runnable() { @Override public void run() { while (!Thread.currentThread().isInterrupted()) { synchronized (lock) { try { printMsgWithThreadName("Wait for notify..."); lock.wait(); printMsgWithThreadName("notify received...\n"); } catch (InterruptedException e) { printMsgWithThreadName("Interrupted!"); return; } } try { Thread.sleep(1000); } catch (InterruptedException e) { printMsgWithThreadName("Interrupted!"); return; } } printMsgWithThreadName("Interrupted!"); } }, "Consumer_Louis"); Thread consumerJimmy = new Thread(new Runnable() { @Override public void run() { while (!Thread.currentThread().isInterrupted()) { synchronized (lock) { try { printMsgWithThreadName("Wait for notify..."); lock.wait(); printMsgWithThreadName("notify received...\n"); } catch (InterruptedException e) { printMsgWithThreadName("Interrupted!"); return; } } try { Thread.sleep(1000); } catch (InterruptedException e) { printMsgWithThreadName("Interrupted!"); return; } } printMsgWithThreadName("Interrupted!"); } }, "Consumer_Jimmy"); Thread notifier = new Thread(new Runnable() { @Override public void run() { while (!Thread.currentThread().isInterrupted()) { synchronized (lock) { printMsgWithThreadName("Begin Notifying..."); lock.notifyAll(); printMsgWithThreadName("End Notifying..."); } try { Thread.sleep(1000); } catch (InterruptedException e) { printMsgWithThreadName("Interrupted!"); return; } } printMsgWithThreadName("Interrupted!"); } }, "notifier"); startThreadStateDetector(consumerLouis); startThreadStateDetector(consumerJimmy); startThreadStateDetector(notifier); consumerLouis.start(); consumerJimmy.start(); notifier.start(); sleepIgnoreInterrupt(5000); consumerLouis.interrupt(); consumerJimmy.interrupt(); notifier.interrupt();}
运行结果为:
Thread-[Consumer_Louis] Wait for notify...Thread-[notifier] Begin Notifying...Thread-[notifier] End Notifying...Thread-[Consumer_Jimmy] Wait for notify...Thread-[Consumer_Louis] notify received...Thread-[notifier] Begin Notifying...Thread-[notifier] End Notifying...Thread-[Consumer_Jimmy] notify received...Thread-[Consumer_Louis] Wait for notify...Thread-[Consumer_Jimmy] Wait for notify...Thread-[notifier] Begin Notifying...Thread-[notifier] End Notifying...Thread-[Consumer_Jimmy] notify received...Thread-[Consumer_Louis] notify received...Thread-[notifier] Begin Notifying...Thread-[notifier] End Notifying...Thread-[Consumer_Jimmy] Wait for notify...Thread-[Consumer_Louis] Wait for notify...Thread-[notifier] Begin Notifying...Thread-[notifier] End Notifying...Thread-[Consumer_Louis] notify received...Thread-[Consumer_Jimmy] notify received...Thread-[Consumer_Louis] Interrupted!Thread-[notifier] Interrupted!Thread-[Consumer_Jimmy] Interrupted!Thread-[Consumer_Louis], States [NEW, RUNNABLE, WAITING, BLOCKED, TIMED_WAITING, TERMINATED]Thread-[notifier], States [NEW, RUNNABLE, BLOCKED, TIMED_WAITING, TERMINATED]Thread-[Consumer_Jimmy], States [NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED]
可以看到每次在notifier调用了notifyAll()之后,Consumer_Louis 和 Consumer_Jimmy 都被同时唤醒。
可以将 lock.notifyAll(); 替换为 lock.notify(); 重新运行程序,将会看见系统每次都将在Consumer_Louis 和 Consumer_Jimmy 之间随机选择一个线程来唤醒。
- Java中的sleep() | wait() | notify() | notifyAll()
- Java:sleep、wait、notify、notifyAll
- sleep & wait | notify | notifyAll
- sleep & wait | notify | notifyAll
- wait,notify,notifyAll,sleep
- java join sleep wait notify notifyAll
- Java之wait()/sleep()和notify()/notifyAll()
- java之sleep, wait, notify, notifyall
- java多线程wait,sleep,notify,notifyAll
- sleep synchronized wait notify notifyAll
- synchronized,sleep,wait,notify,notifyAll
- 多线程wait-notify;notifyall.sleep
- wait|notify|notifyAll|sleep|volatile
- wait, sleep, notify, notifyall, join
- 关于Java多线程中的wait()、sleep()、notify()和notifyAll()的简单介绍和使用
- Java多线程:notify/notifyAll/wait/sleep在多线程中的区别于使用
- Java中的wait、notify、notifyall方法
- Java线程中的wait, notify and notifyAll
- POJ 3250 hair cut
- NOIP2007 矩阵取数游戏 [dp] [高精度]
- PC端和移动端相应Enter
- 对恶意APP"淘宝宝贝分享图"的逆向分析
- 51. N-Queens
- Java中的sleep() | wait() | notify() | notifyAll()
- java基础理论
- rails动态定义实例方法和类方法
- 常见的web安全问题及防御
- SD卡相关操作
- 81. Search in Rotated Sorted Array II
- 网教 7.蜜汁序列
- 第十三章 字符串 正则表达式
- 点击键盘移动物体