1. Java线程的调度和管理
2. 线程的调度与时间片
1. CPU时间片2. 线程的调度
1. 分时调度2. 抢占式调度 3. Java的线程优先级 2. 线程的生命周期
1. 线程的6种状态
1. NEW 新建2. RUNNABLE 运行3. TERMINATED 终止4. TIMED_WAITING 限时等待
1. Java线程的调度和管理现在的操作系统已经提供了非常强大的线程管理能力,Java不需要再进行独立的线程管理和调度,而是将线程的调度和管理的工作交给了操作系统去完成。
2. 线程的调度与时间片 1. CPU时间片
现在的CPU的算力已经很快了,2Ghz每秒就可以运行20亿次计算。所以可以将CPU的时间从毫秒级别进行分段,每一段被叫做一个CPU时间片。对于不同的操作系统,不同的CPU,CPU时间片的时间长度也都不相同。
目前操作系统对于线程的调度,都是基于CPU时间片对线程进行调度的。每个线程只有获得了CPU时间片才可以执行命令。
获得了CPU时间片的线程就处于运行状态,没有获得CPU时间片,但是在等待获取CPU时间片去运行的线程就处于就绪状态。
2. 线程的调度线程的调度目前主要有两种方式:分时调度 和 抢占式调度
1. 分时调度CPU将时间片平均的分配给每个线程,所有CPU轮流占用CPU时间片。
这种方式在CPU时间片的调度上对于每个线程是公平的,类似生活中的排队,一个接一个的占用CPU时间片,用过之后再去队尾排队。
系统按照线程的优先级对线程进行调度。若线程的优先级相同,则随机挑选一个线程分配CPU时间片。
理论上讲,在一段时间以内,优先级高的线程获得CPU时间片的次数更多。
由于现在大多数操作系统的线程调度模型都是抢占式的,而Java的线程调度又是委托给操作系统的,所以Java中的线程调度方式,也是抢占式的。
3. Java的线程优先级public class TestThreadPriority {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
Demo[] demos = new Demo[10];
// 创建10个线程,分别将线程的优先级设置为0-10
for (int i = 0; i < demos.length; i++) {
demos[i] = new Demo();
demos[i].setPriority(i + 1);
}
// 启动线程
for (int i = 0; i < demos.length; i++) {
demos[i].start();
}
// 让异步线程运行0.1s
Thread.sleep(100);
// 将异步线程停止,stop方法已经弃用了,这里只是演示使用
for (int i = 0; i < demos.length; i++) {
demos[i].stop();
}
long end = System.currentTimeMillis();
// 这里计算了一下10个线程从创建到结束真正花费了多少时间
System.out.println("main线程启动线程到关闭线程花费了:" + (end - start) + "毫秒");
// 打印类中的num值,看变成了多少
// 从这个值的大小,大致可以知道每个线程运行的时间比重
for (int i = 0; i < demos.length; i++) {
System.out.println("线程优先级为:" + demos[i].getPriority() + ",num为:" + demos[i].num);
}
}
}
class Demo extends Thread {
public long num = 0;
@Override
public void run() {
for (long i = 0; ; i++) {
num++;
}
}
}
我电脑的运行结果如下:
main线程启动线程到关闭线程花费了:8262毫秒 线程优先级为:1,num为:9122402 线程优先级为:2,num为:0 线程优先级为:3,num为:9154161 线程优先级为:4,num为:0 线程优先级为:5,num为:24016156 线程优先级为:6,num为:0 线程优先级为:7,num为:2519810813 线程优先级为:8,num为:2546229794 线程优先级为:9,num为:2615067015 线程优先级为:10,num为:2603997818
从结果大致也可以看出:
- 整体而言,线程的优先级越高,线程获得执行的机会就越大。优先级>6的和<=6的num大小不在一个数量级上执行机会的获取具有随机性,优先级高的获得的执行次数不一定多。例如优先级为2,4,6的线程就没有获得时间片去执行,比他们优先级低的反而还获得了时间片。
2. 线程的生命周期
Java中线程的生命周期有6种状态。
1. 线程的6种状态Thread类中使用threadStatus属性保存线程状态,使用getState()方法获取线程状态。
// 使用int类型保存线程状态
private volatile int threadStatus;
// 获取线程状态
public State getState() {
// get current thread state
return jdk.internal.misc.VM.toThreadState(threadStatus);
}
其中State类是Thread类的一个内部枚举类,如下:
public enum State {
NEW, // 新建
RUNNABLE, // 运行,包括操作系统的运行、就绪状态
BLOCKED, // 阻塞
WAITING, // 等待
TIMED_WAITING, // 限时等待
TERMINATED; // 终止
}
1. NEW 新建
当线程被创建出来但是还没有调用start() 方法的时候是新建状态
验证代码:
public class TestThreadState {
public static void main(String[] args) {
Thread thread = new Thread();
System.out.println("线程状态为:" + thread.getState());
}
}
输出结果为:
线程状态为:NEW2. RUNNABLE 运行
在Java中,调用了start()方法之后,Thread的状态就会变成RUNNABLE,但是这时候run()方法不一定会被执行,因为线程的执行是需要CPU时间片的。
只有获取了CPU时间片的时候,在操作系统中才是运行状态,在一切都准备好了,就是在等待CPU时间片的时候,被称作就绪状态。
但是在Java的线程类中,操作系统的运行状态 和 就绪状态 都被使用RUNNABLE 状态来表示了。这点跟操作系统的状态是不同的。
验证代码:
public class TestThreadState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread();
thread.start();
System.out.println("线程的状态为:" + thread.getState());
}
}
运行结果为:
线程的状态为:RUNNABLE3. TERMINATED 终止
在线程任务执行完毕之后,状态就会变成终止状态。不管这个结束是因为方法执行完毕还是中途抛出了异常而没有被捕获而终止,都是终止状态。
验证代码:
public class TestThreadState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread();
thread.start();
// 线程执行完毕后,状态变为 terminated
Thread.sleep(100);
System.out.println("线程的状态为:" + thread.getState());
// 运行过程中抛出异常没有捕获,状态变为 terminated
Thread exceptionThread = new Thread(() -> {
int i = 1 / 0;
});
exceptionThread.start();
Thread.sleep(100); // 睡眠0.1秒,等异常出现
System.out.println("exceptionThread线程的状态为:" + exceptionThread.getState());
}
}
运行结果为:
线程的状态为:TERMINATED Exception in thread "Thread-1" java.lang.ArithmeticException: / by zero at com.wang.thread.TestThreadState.lambda$main$0(TestThreadState.java:17) at java.base/java.lang.Thread.run(Thread.java:833) exceptionThread线程的状态为:TERMINATED4. TIMED_WAITING 限时等待
可以让线程进入这个状态的操作有:
- Thread.sleep(…)方法Object.wait() :带时限的抢占对象的monitor锁Thread.join():带时限的线程合并LockSupport.parkNanos():让线程等待,以纳秒为单位LockSupport.parkUntil():让线程等待,时间可以灵活设置
public class TestTimedWaitingState {
public static void main(String[] args) throws InterruptedException {
Thread demo = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
demo.start();
// 睡10毫秒,等待线程启动
Thread.sleep(10);
System.out.println("sleep时候线程状态为:" + demo.getState());
}
}
运行结果:
sleep时候线程状态为:TIMED_WAITING



