public class Object{
/**
调用对象的此方法,会让当前线程等待,直到另外一个线程(必须先获得该对象的锁),
调用了该对象的notify方法或者notifyAll通知方法或者指定的时间到了
* Causes the current thread to wait until either another thread invokes the
* {@link java.lang.Object#notify()} method or the
* {@link java.lang.Object#notifyAll()} method for this object, or a
* specified amount of time has elapsed.
* <p>
当前的线程必须持有此对象的锁,才能调用此对象的wait方法
* The current thread must own this object's monitor.
* <p>
此方法会让当前线程放到此对象的waitSet中等待,并且放弃此对象的这把锁。当前线程将不可用,不会被调度,进入休眠。
一直到下面四件事之一发生才会苏醒:
1. 其它的线程调用了该对象的notify方法,并且这个休眠的线程刚好随机被唤醒了
2. 其它的线程调用了该对象的notifyAll方法
3. 其它的线程中断了这个正在waitSet中的线程
(注意:这里测试了下,中断这个处在WaitSet中的线程,但是它并不是马上抛出中断异常,
如果这把锁被别的线程拿了还没还回来的话,那就等这把锁被释放了之后,再抛出中断异常,
如果这把锁没有被拿的话,那就抛出中断异常)。也可以这样理解,它要竞争到锁,才能接着执行(抛异常)
4. 指定的时间已经过了。但是如果指定的时间是0,那就不考虑时间,一直等到被其它线程唤醒
* This method causes the current thread (call it <var>T</var>) to
* place itself in the wait set for this object and then to relinquish
* any and all synchronization claims on this object. Thread <var>T</var>
* becomes disabled for thread scheduling purposes and lies dormant
* until one of four things happens:
* <ul>
* <li>Some other thread invokes the {@code notify} method for this
* object and thread <var>T</var> happens to be arbitrarily chosen as
* the thread to be awakened.
* <li>Some other thread invokes the {@code notifyAll} method for this
* object.
* <li>Some other thread {@linkplain Thread#interrupt() interrupts}
* thread <var>T</var>.
* <li>The specified amount of real time has elapsed, more or less. If
* {@code timeout} is zero, however, then real time is not taken into
* consideration and the thread simply waits until notified.
* </ul>
以上四件事之一发生,线程会从这个对象的waitSet中被移除,并且恢复线程调用。这个线程会继续进入到这个对象的
entryList中竞争,一旦它获得了锁,它就跟原先调用wait方法时的状态一样,并且从wait方法的调用处返回。
* The thread <var>T</var> is then removed from the wait set for this
* object and re-enabled for thread scheduling. It then competes in the
* usual manner with other threads for the right to synchronize on the
* object; once it has gained control of the object, all its
* synchronization claims on the object are restored to the status quo
* ante - that is, to the situation as of the time that the {@code wait}
* method was invoked. Thread <var>T</var> then returns from the
* invocation of the {@code wait} method. Thus, on return from the
* {@code wait} method, the synchronization state of the object and of
* thread {@code T} is exactly as it was when the {@code wait} method
* was invoked.
* <p>
一个线程可能在没有 “被唤醒”,“超时”,“中断”的情况下被唤醒,这就是所谓的虚假唤醒。
尽管在实践中很少发生,应用应该要保证线程被唤醒后判断下它的条件是否被满足。换句话说,
wait的调用应该要放到循环里面,就像下面这样。详细的可以看下Doug Lea的并发编程的书
* A thread can also wake up without being notified, interrupted, or
* timing out, a so-called <i>spurious wakeup</i>. While this will rarely
* occur in practice, applications must guard against it by testing for
* the condition that should have caused the thread to be awakened, and
* continuing to wait if the condition is not satisfied. In other words,
* waits should always occur in loops, like this one:
* <pre>
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait(timeout);
* ... // Perform action appropriate to condition
* }
* </pre>
* (For more information on this topic, see Section 3.2.3 in Doug Lea's
* "Concurrent Programming in Java (Second Edition)" (Addison-Wesley,
* 2000), or Item 50 in Joshua Bloch's "Effective Java Programming
* Language Guide" (Addison-Wesley, 2001).
*
如果当前线程在调用wait之前被其它线程调用了中断或者进入了wait之后被调用了中断,就会抛出中断异常。
这个异常要等到对象的锁状态恢复了的时候才会被抛出。(前一种情况,肯定是先拿到了锁对象,才能调用wait,
所以会立即抛异常;后面这种情况,那就看wait放弃了这把锁之后,其它的持锁线程是否归还了锁;)
还注意一下这个中断,中断只有在线程对象调用了start方法,开启线程之后,去中断才有作用。
* <p>If the current thread is {@linkplain java.lang.Thread#interrupt()
* interrupted} by any thread before or while it is waiting, then an
* {@code InterruptedException} is thrown. This exception is not
* thrown until the lock status of this object has been restored as
* described above.
*
注意下:这个wait方法会把当前线程放到此对象的waitSet中等待,只会释放这个对象的锁。
如果这个线程还持有其它锁,那么其他锁是不会被释放的。
* <p>
* Note that the {@code wait} method, as it places the current thread
* into the wait set for this object, unlocks only this object; any
* other objects on which the current thread may be synchronized remain
* locked while the thread waits.
* <p>
这个方法只能对象的锁持有者才能调用!!!看notify方法参考线程成为锁持有者的途径
* 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.
*
参数:最大等待时间,时间是负数会抛出异常
如果当前的线程没有获取到对象的锁,将会抛出非法异常
如果当前线程在调用wait之前被其它线程调用了中断或者进入了wait之后被调用了中断,就会抛出中断异常。
当前线程的中断状态会在异常被抛出时置为false
* @param timeout the maximum time to wait in milliseconds.
* @throws IllegalArgumentException if the value of timeout is
* negative.
* @throws IllegalMonitorStateException if the current thread is not
* the owner of the object's monitor.
* @throws 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 native void wait(long timeout) throws InterruptedException;
/**
随机唤醒一个在该对象的waitSet中等待的线程。
一个线程通过调用某个对象的wait方法,进入到这个对象的waitset中等待。
* 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>
被唤醒的线程还不能继续运行,它必须进入到entrylist中和其它竞争这把锁的线程一起争夺这把锁。
(这也就是wait方法为什么要写在同步代码块里面的原因吧,因为wait方法还在同步代码块里面,
刚刚被唤醒,仍然要去争夺锁对象)
举个例子:被唤醒的线程相对于其它竞争同一把所的其它线程而言没有任何优先权或滞后权
* 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.
这个方法只能被锁对象的持有者调用!!!
一个线程称为锁对象的持有者可以有3种方式:
1. 执行一个对象的同步方法
2. 执行synchronized同步方法(锁对象为this)
3. 执行static修饰的同步方法(锁对象为class)
* <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.
*
* @throws 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();
}
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis(); // 进入代码的时间
long now = 0; // 花费的时间
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
// 因为wait方法会出现虚假唤醒的情况,所以要用循环,防止虚假唤醒
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now; // 还剩多久的等待时间
if (delay <= 0) {
// 如果已经等完了,那就跳出循环,所以时间的准确度在于wait方法
break;
}
wait(delay); // 进入当前的线程对象的waitset种等待
now = System.currentTimeMillis() - base; // 计算等了多久
}
}
}