线程协作
线程状态
Java中的线程状态可以分为以下5种,new,runnable,running,blocked,dead;
- new: 线程创建完毕,还没有调用start方法;
- runnable: 调用start()方法后,线程进入就绪状态;此时由线程调度程序(thread scheduler)调度;
- running: 运行状态,就绪线程取得cpu执行权,执行run()方法;
- blocked: 阻塞状态,线程并没有执行完成就让出cpu执行权;
- dead: 线程任务执行完成或异常终止
wait
public final void wait() throws InterruptedException {
wait(0);//timeout
}
使当前线程进入阻塞状态,notify()与notifyall()可以唤醒
public final native void wait(long timeout) throws InterruptedException;
指定了一个long型的时间戳,表示如果在指定时间内线程没有被notify()或notifyall()唤醒,线程也会自动苏醒
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
都差不多;
wait()方法在使用过程中,需抛出InterruptedException;
单纯的使用wait()可能会抛出IllegalMonitorStateException,意为
线程试图等待对象的监视器或者试图通知其他正在等待对象监视器的线程,但本身没有对应的监视器的所有权。 因为wait()是Object类的方法,底层是通过监视器锁实现的,抛出异常的原因是调用wait()时没有取到monitor的所有权。此时的话要使用Synchronized关键字
/**
* Thrown to indicate that a thread has attempted to wait on an
* object's monitor or to notify other threads waiting on an object's
* monitor without owning the specified monitor.
*
* @author unascribed
* @see java.lang.Object#notify()
* @see java.lang.Object#notifyAll()
* @see java.lang.Object#wait()
* @see java.lang.Object#wait(long)
* @see java.lang.Object#wait(long, int)
* @since JDK1.0
*/
public class IllegalMonitorStateException extends RuntimeException {
private static final long serialVersionUID = 3713306369498869069L;
/**
* Constructs an <code>IllegalMonitorStateException</code> with no
* detail message.
*/
public IllegalMonitorStateException() {
super();
}
/**
* Constructs an <code>IllegalMonitorStateException</code> with the
* specified detail message.
*
* @param s the detail message.
*/
public IllegalMonitorStateException(String s) {
super(s);
}
}
notify/notifyAll
notify
/**
* Wakes up a single thread that is waiting on this 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();
在一个对象上调用notify(),可以唤醒对应对象monitor上等待的线程
public final native void notifyAll();
调用wait()后,线程是会释放monitor对象的所有权的;
一个线程调用wait()阻塞后并不意味着它被唤醒(超时唤醒或者notify/notifyall)后就会被执行,它还需要竞争到monitor
注:以上3个方法是位于object类下面的,并不是位于thread类下面的,因为所有的类都是Object的子类,wait()等待的对象其实是monitor。sleep()/yield()/join是位于thread类下面的。
sleep
sleep()方法的作用是让当前线程暂停指定的时间(毫秒);sleep()只是暂时让出cpu的执行权,而wait()会释放锁,这是根本区别。
/**
* 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;
yield
/**
* A hint to the scheduler that the current thread is willing to yield
* its current use of a processor. The scheduler is free to ignore this
* hint.
*
* <p> Yield is a heuristic attempt to improve relative progression
* between threads that would otherwise over-utilise a CPU. Its use
* should be combined with detailed profiling and benchmarking to
* ensure that it actually has the desired effect.
*
* <p> It is rarely appropriate to use this method. It may be useful
* for debugging or testing purposes, where it may help to reproduce
* bugs due to race conditions. It may also be useful when designing
* concurrency control constructs such as the ones in the
* {@link java.util.concurrent.locks} package.
*/
public static native void yield();
暂停当前线程,将其从running状态转换成runnable状态,但是不能指定暂停时间,也不能保证当前线程马上停止;本身使用的场景就比较少
join
//-------------->1
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(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
//-------------->2
public final void join() throws InterruptedException {
join(0);
}
//-------------->3
public final synchronized void join(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
join(millis);
}
join方法的作用是父线程等待子线程执行完成后再执行的,通过wait()来将线程阻塞,直到join执行完。
当join执行完之后thread.start会自动唤醒主线程继续执行。如果没有使用join(),线程并发执行,使用后,线程顺序执行。