多线程原理与实战【03 线程的核心原理】
线程的核心原理
线程的调度与时间片
时间片:CPU在时间毫秒在维度进行分段,每一小段叫作一个CPU时间片。
调度:分时调度模型(系统平均分配CPU在时间片)、抢占式调度模型(系统按优先级分配CPU时间片,优先级相同随机选择一个,优先级高在线程获得CPU时间片相对多一些)
线程的优先级
public class Thread implements Runnable {
//该属性保存一个Thread实例在优先级,即[1,10]的值
private int priority;
//最小值
public final static int MIN_PRIORITY = 1;
//默认值
public final static int NORM_PRIORITY = 5;
//最大值
public final static int MAX_PRIORITY = 10;
//获取线程的优先级
public final int getPriority() {
return priority;
}
//设置线程在优先级
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
}
package com.ryder.code;
public class PriorityDemo {
static class PrioritySetThread extends Thread {
static int threadNo = 1;
public PrioritySetThread() {
super("thread-" + threadNo);
threadNo++;
}
public long opportunities = 0;
public void run() {
for (int i = 0; i < 20000000000L; i++) {
opportunities++;
}
}
}
public static void main(String[] args) throws InterruptedException {
PrioritySetThread[] threads = new PrioritySetThread[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new PrioritySetThread();
//设置优先级[1,10]
threads[i].setPriority(i + 1);
}
for (int i = 0; i < threads.length; i++) {
threads[i].start();
}
Thread.sleep(1000);
for (int i = 0; i < threads.length; i++) {
threads[i].stop();
}
for (int i = 0; i < threads.length; i++) {
System.out.println(threads[i].getName() +
"---优先级:" + threads[i].getPriority() +
"---机会值: " + threads[i].opportunities);
}
}
}
thread-1---优先级:1---机会值: 0
thread-2---优先级:2---机会值: 0
thread-3---优先级:3---机会值: 53761
thread-4---优先级:4---机会值: 0
thread-5---优先级:5---机会值: 23844913
thread-6---优先级:6---机会值: 2532408527
thread-7---优先级:7---机会值: 10179683260
thread-8---优先级:8---机会值: 10270675487
thread-9---优先级:9---机会值: 6553110054
thread-10---优先级:10---机会值: 10436151582
某个线程的实例属性opportunities的值越大,就表明获得的CPU时间片越多。
线程的生命周期
public enum State {
NEW, //新建
RUNNABLE, //可执行:就绪、运行状态
BLOCKED, //阻塞
WAITING, //等待
TIMED_WAITING, //计时等待
TERMINATED; //终止
}
package com.ryder.code;
import java.util.ArrayList;
import java.util.List;
public class StatusDemo {
//每个线程执行的轮次
public static final long MAX_COUNT = 5;
//线程编号
public static int threadNo = 0;
//全局的静态线程列表
static List<Thread> threadList = new ArrayList<>();
//输出静态线程列表中每个线程的状态
private static void printThreadStatus() {
for (Thread thread : threadList) {
System.out.println(thread.getName() + "状态为:" + thread.getState());
}
}
//向全局的静态线程列表加入线程
private static void addStatusThread(Thread thread) {
threadList.add(thread);
}
static class StatusDemoThread extends Thread {
public StatusDemoThread() {
super("statusPrintThread" + (++threadNo));
addStatusThread(this);
}
@Override
public void run() {
System.out.println(getName() + ",状态为" + getState());
for (int i = 0; i < MAX_COUNT; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
printThreadStatus();
}
System.out.println(getName() + "---运行结束");
}
}
public static void main(String[] args) throws InterruptedException {
addStatusThread(Thread.currentThread());
Thread statusDemoThread01 = new StatusDemoThread();
System.out.println(statusDemoThread01.getName() + "--状态为:" + statusDemoThread01.getState());
Thread statusDemoThread02 = new StatusDemoThread();
System.out.println(statusDemoThread02.getName() + "--状态为:" + statusDemoThread02.getState());
Thread statusDemoThread03 = new StatusDemoThread();
System.out.println(statusDemoThread03.getName() + "--状态为:" + statusDemoThread03.getState());
statusDemoThread01.start();
Thread.sleep(500);
statusDemoThread02.start();
Thread.sleep(500);
statusDemoThread03.start();
}
}
statusPrintThread1--状态为:NEW
statusPrintThread2--状态为:NEW
statusPrintThread3--状态为:NEW
statusPrintThread1,状态为RUNNABLE
main状态为:RUNNABLE
statusPrintThread1状态为:RUNNABLE
statusPrintThread2状态为:RUNNABLE
statusPrintThread3状态为:NEW
statusPrintThread2,状态为RUNNABLE
main状态为:TIMED_WAITING
main状态为:TIMED_WAITING
statusPrintThread1状态为:RUNNABLE
statusPrintThread2状态为:RUNNABLE
statusPrintThread3状态为:NEW
statusPrintThread1状态为:RUNNABLE
statusPrintThread2状态为:TIMED_WAITING
statusPrintThread3状态为:NEW
statusPrintThread3,状态为RUNNABLE
main状态为:TERMINATED
statusPrintThread1状态为:RUNNABLE
main状态为:TERMINATED
statusPrintThread1状态为:BLOCKED
main状态为:TERMINATED
statusPrintThread1状态为:BLOCKED
statusPrintThread2状态为:BLOCKED
statusPrintThread3状态为:RUNNABLE
statusPrintThread2状态为:BLOCKED
statusPrintThread2状态为:RUNNABLE
statusPrintThread3状态为:TIMED_WAITING
statusPrintThread3状态为:TIMED_WAITING
main状态为:TERMINATED
main状态为:TERMINATED
statusPrintThread1状态为:BLOCKED
statusPrintThread2状态为:RUNNABLE
statusPrintThread3状态为:RUNNABLE
main状态为:TERMINATED
statusPrintThread1状态为:RUNNABLE
statusPrintThread2状态为:TIMED_WAITING
statusPrintThread3状态为:RUNNABLE
statusPrintThread1状态为:TIMED_WAITING
statusPrintThread2状态为:TIMED_WAITING
statusPrintThread3状态为:RUNNABLE
main状态为:TERMINATED
main状态为:TERMINATED
statusPrintThread1状态为:RUNNABLE
statusPrintThread2状态为:RUNNABLE
statusPrintThread3状态为:BLOCKED
main状态为:TERMINATED
statusPrintThread1状态为:RUNNABLE
statusPrintThread2状态为:TIMED_WAITING
statusPrintThread3状态为:RUNNABLE
statusPrintThread1状态为:RUNNABLE
statusPrintThread2状态为:TIMED_WAITING
statusPrintThread3状态为:TIMED_WAITING
statusPrintThread1---运行结束
main状态为:TERMINATED
main状态为:TERMINATED
statusPrintThread1状态为:TERMINATED
statusPrintThread2状态为:RUNNABLE
statusPrintThread3状态为:RUNNABLE
statusPrintThread1状态为:TERMINATED
statusPrintThread2状态为:RUNNABLE
statusPrintThread3状态为:TIMED_WAITING
statusPrintThread2---运行结束
main状态为:TERMINATED
statusPrintThread1状态为:TERMINATED
statusPrintThread2状态为:TERMINATED
statusPrintThread3状态为:RUNNABLE
statusPrintThread3---运行结束
通过结果可以看出来,新建之后,没有启动之前为NEW,调用了start()之后,状态为RUNNABLE,调用Thread.sleep()方法后,线程状态变为TIMED_WAITING,等结束后又变为RUNNABLE,线程执行完成后,状态为TERMINATED。
使用Jstack工具查看线程状态
有时,服务器的CPU占用率一直很高,程序是正常运行的,那么如何查看占用CPU的线程状态呢?
有一种比较快捷的办法就是使用Jstack工具。
Jstack 命令语法格式
jstack //pid 表示java进程id,可以用jps命令查看
Jstack指令输出的重要信息:
- tid: 线程实例在JVM进程中的id
- nid: 线程实例在操作系统中对应的底层线程的线程id
- prio: 线程实例在JVM进程中的优先级
- os_prio: 线程实例在操作系统中对应的底层线程的优先级
- 线程状态:runnable 、waiting 、blocked等。