看了一遍thinking in java 没懂,看了中文版Java高并发的书才了解。我跪着来学习了
join
Thread 的join和sleep一样是一个可中断的方法,如果有其他线程执行了对当前线程的interrupt操作,也会捕获到中断信号,并擦除线程的interrupt标识,Thread的API提供了3种不同的join方法。
1. public final void join() throws InterruptedException
2. public final synchronized void join(long millis, int nanos) throws InterruptedException
3. public final synchronized void join(long millis)throws InterruptedException
join某个线程A,会使当前线程B进入等待,直到线程A结束生命周期,或者到达给定的时间,那么在此期间B线程是出于BLOCKED的,而不是A线程。
举个?
import java.util.stream.IntStream;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static java.util.stream.Collectors.toList;
public class ThreadJoin {
public static void main(String[] args) throws InterruptedException{
// 1.定义两个线程,并保存在threads中
List<Thread> threads=IntStream.range(1,3).mapToObj(ThreadJoin::create).collect(toList());
// 2 启动这两个线程
threads.forEach(Thread::start);
// 3.执行这两个线程join方法
for(Thread thread:threads){
thread.join();
}
// 4. main线程循环输出
for(int i=0; i<10;i++){
System.out.println(Thread.currentThread().getName()+"#"+i);
shortSleep();
}
}
//构造简单的线程,每个线程简单循环输出
private static Thread create(int seq){
return new Thread(()->{
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"#"+i);
shortSleep();
}
},String.valueOf(seq));
}
private static void shortSleep() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
结合Java8的语法,创建了两个线程,分别启动,并且调用了每个线程的join方法(注意:join方法是被主线程调用的,因此在第一个线程生命周期没有结束时,第二个线程的join不会被执行,但是此时第二个线程已经启动了),运行上面程序,会发现线程一和线程二会交替的输出直到他们结束生命周期,main线程的循环才开始运行。若将注释3的join全部注释,则三个线程交替输出。
- join会使当前线程永远地等待下去,直到期间被另外的线程中断,或者join的线程执行结束,或者指定的毫秒数到达,当前的线程也会退出阻塞。
问:如果一个线程已经结束生命周期,那么调用他的join方法的当前线程会被阻塞吗?
试了下,好像不会被阻塞
yield
yield 方法属于启发式的方法,提醒调度器“我愿意放弃当前的CPU资源”。如果CPU的资源不紧张,则会忽略这种提醒。
调用yield方法会使得当前线程从RUNNING状态切换到RUNNABLE状态,一般不常用此方法
import java.util.stream.IntStream;
public class ThreadYield {
public static void main(String[] args) {
IntStream.range(0,2).mapToObj(ThreadYield::create).forEach(Thread::start);
}
private static Thread create(int index){
return new Thread(()->{
// if(index==0)
// Thread.yield();
System.out.println(index);
});
}
}
如上程序运行很多次,数字0和1的输出顺序可能不一定,但是当取消注释,顺序将固定成0,1。这是因为当第一个线程获得CPU资源,他会比较谦虚,主动告诉CPU放弃自己的资源,但是yield只是一个hint提示,并不是每次CPU都会满足yield的提示。
yield和sleep的区别
在jdk1.5以前的版本中yield方法事实上调用了sleep(0),但是他们存在本质的区别
- sleep会导致当前线程暂停指定的时间,没有CPU时间片的消耗。
- yield只是对CPU调度器的一个提示,如果没有忽略这个提示,他会导致线程上下文切换。
- sleep会使线程短暂的block。会在给定时间内释放CPU资源。
- yield会使RUNNING状态的线程进入RUNNABLE状态(如果没被忽略)。
- sleep几乎百分百文完成给定时间的休眠,而yield的提示并不一定能担保。
- 一个线程sleep另一个线程interrupt会捕获到中断信号,而yield则不会。
- sleep不会放弃对monitor锁的所有权