Java线程中yield与join方法的区别
周sir |
2016年4月29日 |
多线程编程 |
0 条评论 | 1615
多线程问题常被面试官问到。即便日常很少写复杂并发,弄清调度和优先级也能增加信心。此前讨论过 wait() 和 sleep() 的区别,这里对比 join() 与 yield()。原文转自 ImportNew。
一、Java 线程调度背景
JVM 必须实现一个基于优先级的调度程序:每个线程有一个正整数优先级,开发者可以改,JVM 不会因为线程已经跑了一段时间就擅自改优先级。约定是操作系统应选择当前最高优先级的 Java 线程运行;更高优先级到来时可以抢占低优先级。这个约定对操作系统并不总是成立,有时仍可能跑低优先级线程。
Java 并不限定必须用时间片,但多数操作系统会。抢占和时间片常被混淆:抢占指高优先级可以压过低优先级;同优先级之间不能互相抢占,通常靠时间片轮转,但那不是 Java 规范的硬性要求。
二、理解线程优先级
尤其对理解 yield() 很重要:
-
-
范围 1 到 10:10 最高,1 最低,5 普通。
-
最高优先级在执行时被给予优先,但不保证 start 后立刻进入运行。
-
当前正在运行的线程,相对线程池里等待的线程,往往拥有更高或至少不更低的优先级。
-
由调度程序决定谁真正执行;用
t.setPriority() 设定,最好在 start 之前。
-
可用常量 MIN_PRIORITY、MAX_PRIORITY、NORM_PRIORITY。
三、yield() 方法
yield 的意思是放手、放弃。调用它等于告诉虚拟机:我乐意让出处理器。这只是暗示,调度器可以忽略。Thread 中定义为:
public static native void yield();
示例:生产者设为最低优先级,消费者最高。不调用 yield 时,通常消费者先全部打完再打生产者;调用 yield 后,两个线程更可能交替打印。
package test.core.threads;
public class YieldExample {
public static void main(String[] args) {
Thread producer = new Producer();
Thread consumer = new Consumer();
producer.setPriority(Thread.MIN_PRIORITY);
consumer.setPriority(Thread.MAX_PRIORITY);
producer.start();
consumer.start();
}
}
class Producer extends Thread {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("I am Producer : Produced Item " + i);
Thread.yield();
}
}
}
class Consumer extends Thread {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("I am Consumer : Consumed Item " + i);
Thread.yield();
}
}
}
四、join() 方法
在某个线程实例上调用 join(),当前正在运行的线程会阻塞,直到该实例执行结束(“等这条线程死掉”)。也可以设超时,超时后主线程与任务线程重新平等竞争。join 依赖操作系统计时,不要假定它精确等到你指定的毫秒数。和 sleep 一样,join 通过抛出 InterruptedException 响应中断。
public final void join() throws InterruptedException
package test.core.threads;
public class JoinExample {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("First task started");
System.out.println("Sleeping for 2 seconds");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("First task completed");
}
});
Thread t1 = new Thread(new Runnable() {
public void run() {
System.out.println("Second task completed");
}
});
t.start(); // Line 15
t.join(); // Line 16:等 t 结束再启动 t1
t1.start();
}
}
// Output:
// First task started
// Sleeping for 2 seconds
// First task completed
// Second task completed
| 方法 |
作用 |
保证? |
| yield() |
提示让出 CPU 给同优先级线程 |
不保证,调度器可忽略 |
| join() |
当前线程阻塞直到目标线程结束 |
会等到结束(可设超时) |
一句话总结:yield 只是让出 CPU 的暗示,join 是实打实等到另一条线程结束;优先级能影响调度,但不能保证顺序。
转载请注明来源:Java线程中yield与join方法的区别
我是周sir,这是我的博客。致力于分享我学会的技术和优秀的文章。微信公众号 “周sir专栏” 欢迎大家关注。