一、java 线程调度的背景
java
虚拟机要求在多线程中实现 preemptive
和priority-based
调度,这意味着java
中每一个线程被分配了特定的优先级,正整数在定义好的范围内不断减。优先级可以通过开发者改变但是java
虚拟机从不改变线程的优先级,即使线程已经运行了一段时间。
优先级的值很重要,因为这是java
虚拟机和底部的操作系统的契约,操作系统必须选择一个最高优先级的java
线程运行。这就是我们平时讲的java
实现了一个priority-based
的调度。调度的实现使用的是preemptive方式,也就是说高优先级的线程来到之后,不管低优先级的线程是否运行线程都会中断。然而和操作系统间的契约并不是绝对的,操作系统也可以选择低优先级的线程运行
二、线程的优先级
- 在不指定的情况下,所有的线程的优先级都是正常的。
- 优先级的范围从
1
到10
,10
是最高优先级,1
是最低优先级,5
是正常优先级。 - 最高优先级的线程有执行的趋向,但是不能保证这一线程一定会在它开始的时候执行。
- 当前执行的线程和线程池中等待的线程相比或许有比较高的优先级。
- 线程调度决定哪个线程执行。
setPriority()
方法可以被用来设置线程的优先级。- 线程的优先级应该在
start()
方法调用之前被设置。 - 你可以使用常量
MIN_PRIORITY
,MAX_PRIORITY
和NORM_PRIORITY
来设置优先级
三、yield方法
理论上讲,yield
的意思是松开,放弃或者是屈服。一个yield
的线程告诉虚拟机它允许其他的线程被调度它现在所在的位置,这意味着它没有严格的做一些事情。注意这只是一个线索,没有保证什么事情。yield()
调用后线程进入就绪状态
在Thread.java
中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. Yield is a heuristic attempt to improve relative progression between threads that would otherwise over-utilize a CPU.
* Its use should be combined with detailed profiling and benchmarking to ensure that it actually has the desired effect.
*/
public static native void yield();
1、yield
的是静态方法也是native
方法
2、yield
告诉正在执行的线程给线程池中有相同优先级的线程一个机会
3、yield
不能保证正在执行的线程立刻变成Runnable
状态
4、它仅仅可以使一个线程从running
状态变成Runnable
状态,而不是wait
或者blocked
状态
四、join()
方法
线程实例的join()
方法可以被用来join
到线程执行的开始和其他线程执行的结束,所以直到其他线程运行结束这个线程才会执行。如果join
的方法在线程实例中被调用,当前运行的线程会被堵塞,直到线程实例运行完成。
//Waits for this thread to die.
public final void join() throws InterruptedException
在join
方法中设定超时,可以设定在指定的时间内无效。当超时到达,主线程和任务线程都可能被执行,但是,因为有sleep
,join
需要根据OS
的时间规定来执行,所以你不应该假定线程和你指定的时间是一样的,和sleep
一样,Join
相应中断。
thread.Join
把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()
方法,直到线程A执行完毕后,才会继续执行线程B。
这就是一个很小但是很重要的概念的全部。