wait()和sleep()
我们先简单的了解一下wait()和sleep()这两个方法:
首先wait()是属于Object类的方法,从源码给出的解释来看,wait()方法可以做到如下几点:
(1)首先,调用了wait()之后会引起当前线程处于等待状状态。
(2)其次,每个线程必须持有该对象的monitor。如果在当前线程中调用wait()方法之后,该线程就会释放monitor的持有对象并让自己处于等待状态。
(3)如果想唤醒一个正在等待的线程,那么需要开启一个线程通过notify()或者notifyAll()方法去通知正在等待的线程获取monitor对象。如此,该线程即可打破等待的状态继续执行代码。
-
/**
-
* 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)}.
-
* <p>
-
* 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.
-
* <p>
-
* As in the one argument version, interrupts and spurious wakeups are
-
* possible, and this method should always be used in a loop:
-
* <pre>
-
* synchronized (obj) {
-
* while (<condition does not hold>)
-
* obj.wait();
-
* ... // Perform action appropriate to condition
-
* }
-
* </pre>
-
* 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.
-
*
-
* @exception IllegalMonitorStateException if the current thread is not
-
* the owner of the object's monitor.
-
* @exception InterruptedException if any thread interrupted the
-
* current thread before or while the current thread
-
* was waiting for a notification. The <i>interrupted
-
* status</i> of the current thread is cleared when
-
* this exception is thrown.
-
* @see java.lang.Object#notify()
-
* @see java.lang.Object#notifyAll()
-
*/
-
public final void wait() throws InterruptedException {
-
wait( 0);
-
}
代码演示:
-
public class Main {
-
public static void main(String[] args) {
-
Main main = new Main();
-
main.startThread();
-
}
-
-
/**
-
* 线程锁
-
*/
-
private final Object object = new Object();
-
-
/**
-
* 启动线程
-
*/
-
public void startThread() {
-
Thread t = new Thread( new Runnable() {
-
-
public void run() {
-
System.out.println( "开始执行线程。。。");
-
System.out.println( "进入等待状态。。。");
-
synchronized (object) {
-
try {
-
object.wait();
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
}
-
System.out.println( "线程结束。。。");
-
}
-
});
-
t.start();
-
}
-
}
从代码来看,在执行线程和线程结束之间,我们先让该线程获取object对象作为自己的object's monitor,然后调用了object对象的wait()方法从而让其进入等待状态。那么程序运行的结果如下:
程序在未被唤醒之后,将不再打印“线程结束”,并且程序无法执行完毕一直处于等待状态。
sleep()方法来自于Thread类,从源码给出的解释来看,sleep()方法可以做到如下几点:
(1)首先,调用sleep()之后,会引起当前执行的线程进入暂时中断状态,也即睡眠状态。
(2)其次,虽然当前线程进入了睡眠状态,但是依然持有monitor对象。
(3)在中断完成之后,自动进入唤醒状态从而继续执行代码。
-
/**
-
* 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;
代码演示:
-
public class Main {
-
public static void main(String[] args) {
-
Main main = new Main();
-
main.startThread();
-
}
-
-
/**
-
* 启动线程
-
*/
-
public void startThread() {
-
Thread t = new Thread( new Runnable() {
-
-
public void run() {
-
System.out.println( "开始执行线程。。。");
-
System.out.println( "进入睡眠状态。。。");
-
try {
-
Thread.sleep( 3000);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
System.out.println( "线程结束。。。");
-
}
-
});
-
t.start();
-
}
-
}
从运行的结果来看,我们可以看出程序虽然在运行过程中中断了3秒,但是在3秒结束之后依然会继续执行代码,直到运行结束。在睡眠的期间内,线程会一直持有monitor对象。
那么从以上的理论和实践来分析,我们能得出如下结论:
(1)在线程的运行过程中,调用该线程持有monitor对象的wait()方法时,该线程首先会进入等待状态,并将自己持有的monitor对象释放。
(2)如果一个线程正处于等待状态时,那么唤醒它的办法就是开启一个新的线程,通过notify()或者notifyAll()的方式去唤醒。当然,需要注意的一点就是,必须是同一个monitor对象。
(3)sleep()方法虽然会使线程中断,但是不会将自己的monitor对象释放,在中断结束后,依然能够保持代码继续执行。
notify()和notifyAll()
-
/**
-
* Wakes up a single thread that is waiting on this object's
-
* monitor. If any threads are waiting on this object, one of them
-
* is chosen to be awakened. The choice is arbitrary and occurs at
-
* the discretion of the implementation. A thread waits on an object's
-
* monitor by calling one of the {@code wait} methods.
-
* <p>
-
* The awakened thread will not be able to proceed until the current
-
* thread relinquishes the lock on this object. The awakened thread will
-
* compete in the usual manner with any other threads that might be
-
* actively competing to synchronize on this object; for example, the
-
* awakened thread enjoys no reliable privilege or disadvantage in being
-
* the next thread to lock this object.
-
* <p>
-
* This method should only be called by a thread that is the owner
-
* of this object's monitor. A thread becomes the owner of the
-
* object's monitor in one of three ways:
-
* <ul>
-
* <li>By executing a synchronized instance method of that object.
-
* <li>By executing the body of a {@code synchronized} statement
-
* that synchronizes on the object.
-
* <li>For objects of type {@code Class,} by executing a
-
* synchronized static method of that class.
-
* </ul>
-
* <p>
-
* Only one thread at a time can own an object's monitor.
-
*
-
* @exception IllegalMonitorStateException if the current thread is not
-
* the owner of this object's monitor.
-
* @see java.lang.Object#notifyAll()
-
* @see java.lang.Object#wait()
-
*/
-
public final native void notify();
-
/**
-
* Wakes up all threads that are waiting on this object's monitor. A
-
* thread waits on an object's monitor by calling one of the
-
* {@code wait} methods.
-
* <p>
-
* The awakened threads will not be able to proceed until the current
-
* thread relinquishes the lock on this object. The awakened threads
-
* will compete in the usual manner with any other threads that might
-
* be actively competing to synchronize on this object; for example,
-
* the awakened threads enjoy no reliable privilege or disadvantage in
-
* being the next thread to lock this object.
-
* <p>
-
* 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.
-
*
-
* @exception IllegalMonitorStateException if the current thread is not
-
* the owner of this object's monitor.
-
* @see java.lang.Object#notify()
-
* @see java.lang.Object#wait()
-
*/
-
public final native void notifyAll();
notify()实现有序唤醒的思路和实现
-
public class MyThreadFactory {
-
-
// 线程A是否处于等待状态的标志
-
private boolean isThreadAWaiting;
-
// 线程B是否处于等待状态的标志
-
private boolean isThreadBWaiting;
-
// 线程C是否处于等待状态的标志
-
private boolean isThreadCWaiting;
-
-
public MyThreadFactory() {
-
isThreadAWaiting = true;
-
isThreadBWaiting = true;
-
isThreadCWaiting = true;
-
}
-
-
/**
-
* 对象锁
-
*/
-
private final Object object = new Object();
-
-
/**
-
* 该线程作为一个唤醒线程
-
*/
-
public void startWakenThread() {
-
Thread t = new Thread( new Runnable() {
-
-
public void run() {
-
synchronized (object) {
-
System.out.println( "唤醒线程开始执行...");
-
// 首先释放线程A
-
quitThreadA();
-
}
-
}
-
});
-
t.start();
-
}
-
-
/**
-
* 启动线程A
-
*/
-
public void startThreadA() {
-
Thread t = new Thread( new Runnable() {
-
-
public void run() {
-
synchronized (object) {
-
System.out.println( "线程A开始等待...");
-
try {
-
for (; ; ) {
-
if (!isThreadAWaiting) break;
-
object.wait();
-
}
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
System.out.println( "线程A结束...");
-
// 线程A结束后,暂停2秒释放线程B
-
try {
-
Thread.sleep( 2000);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
quitThreadB();
-
}
-
}
-
});
-
t.start();
-
}
-
-
/**
-
* 启动线程B
-
*/
-
public void startThreadB() {
-
Thread t = new Thread( new Runnable() {
-
-
public void run() {
-
synchronized (object) {
-
System.out.println( "线程B开始等待...");
-
try {
-
for (; ; ) {
-
if (!isThreadBWaiting) break;
-
object.wait();
-
}
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
System.out.println( "线程B结束...");
-
// 线程B结束后,暂停2秒释放线程C
-
try {
-
Thread.sleep( 2000);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
quitThreadC();
-
}
-
}
-
});
-
t.start();
-
}
-
-
/**
-
* 启动线程C
-
*/
-
public void startThreadC() {
-
Thread t = new Thread( new Runnable() {
-
-
public void run() {
-
synchronized (object) {
-
System.out.println( "线程C开始等待...");
-
try {
-
for (; ; ) {
-
if (!isThreadCWaiting) break;
-
object.wait();
-
}
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
System.out.println( "线程C结束...");
-
-
try {
-
Thread.sleep( 1000);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
System.out.println( "所有线程执行完毕!");
-
}
-
}
-
});
-
t.start();
-
}
-
-
/**
-
* 线程A退出等待
-
*/
-
private void quitThreadA() {
-
isThreadAWaiting = false;
-
object.notify();
-
}
-
-
/**
-
* 线程B退出等待
-
*/
-
private void quitThreadB() {
-
isThreadBWaiting = false;
-
object.notify();
-
}
-
-
/**
-
* 线程C退出等待
-
*/
-
private void quitThreadC() {
-
isThreadCWaiting = false;
-
object.notify();
-
}
-
}
在以上代码中,我写了三个线程A,B,C用来作为等待线程,并且最后通过一个唤醒线程来唤醒这三个线程。
-
public static void main(String[] args) {
-
MyThreadFactory factory = new MyThreadFactory();
-
factory.startThreadA();
-
factory.startThreadB();
-
factory.startThreadC();
-
-
try {
-
Thread.sleep( 3000);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
factory.startWakenThread();
-
}
最后运行的结果如下: