在Java多线程编程中,会涉及到wait、notify、nptifyAll、yield、join、sleep线程间交互的方法,这些比较晦涩难懂,现在全面介绍下这些方法的使用方式。
1. 总览
这些方法可大致分为两类,一类是继承自Object的方法,全部为native实现,一类是Thread的方法,也都是依托native实现的。
1) 继承自Object
- notify()
- notifyAll()
- wait()
- wait(long timeout)
- wait(long timeout, int nanos)

2) Thread的方法
- static yield()
- static sleep(long millis)
- static sleep(long millis, int nanos)
- join(long millis)
- join(long millis, int nanos)
- join()


2. 线程状态转换
摘自 深入理解Java虚拟机 第三版 12章 Java内存模型与线程 461页

2.使用说明
1) wait/wait(time) 与 notify/notifyAll
- wait、nofity、notifyAll都是操作synchronized锁持有对象的方法,wait表示当前锁对象开启wait等待通知唤醒并交出锁,notify表示通知唤醒一个wait状态的对象锁,notifyAll表示通知唤醒全部wait的对象锁。
- wait、nofity、notifyAll都是配合synchronized使用的,只有锁持有对象才能使用这些方法,否则会报错。
- wait表示一直阻塞,交出锁,wait(long timeout)表示到了设定时间,如果没有被notify通知唤醒,则自己自动继续执行,不过wait点之后的执行需要获取锁,这点要注意。
2) sleep
是Thread的static方法,可直接调用,表示当前线程睡眠指定时间。当线程睡眠时,会阻塞线程,交出cpu。(自行测试)
3) yield
是Thread的static方法,可直接调用,表示让出CPU资源,其他线程线程和自己重新竞争执行机会,不会阻塞线程。
该方法不能保证其他线程能争抢到,有可能还是自己抢到。
- 代码样例
import java.time.LocalTime;
public class YieldTest {
public static void main(String[] args) {
Thread thread = new Thread(new MyThread());
thread.start();
Thread thread2 = new Thread(new MyThread());
thread2.start();
}
public static class MyThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " " + i + " " + LocalTime.now());
Thread.yield();
System.out.println(Thread.currentThread().getName() + " " + i + " yield " + LocalTime.now());
}
}
}
}
4) join/join(time)
join是成员方法,当前线程调用其他线程的join方法,形成阻塞,当调用的线程运行结束时,阻塞结束。
join(time)表示在设置时间内指定线程没有执行完,也结束阻塞,继续执行代码。
如下代码表示主线程调用了thread的join方法,形成阻塞,thread睡了2秒后,主线程继续执行。
- 代码样例
import java.time.LocalTime;
public class JoinTest {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new MyThread());
thread.start();
System.out.println("Main join wait " + LocalTime.now());
thread.join();
System.out.println("Main end " + LocalTime.now());
}
public static class MyThread implements Runnable{
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
- 输出
Main join wait 00:35:33.265
Main end 00:35:35.199
- 源码解读
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) {
//无限等待至该线程可用死亡(!isAlive())
//isAlive与wait都是native方法
while (isAlive()) {
wait(0); // 复用Object的wait方法
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
网友评论