(一)java线程优先级
在Java线程中,通过一个整型成员变量priority来控制优先级,优先级的范围从1~10,在线程构建的时候可以通过setPriority(int)方法来修改优先级,默认优先级是5,优先级高的线程分配CPU时间片的数量要多于优先级低的线程。
获得线程优先级方法为:getPriority()
设置线程优先级方法为:setPriority(int x)
线程的优先级用数字来表示,范围1~10。jdk中提供了常量类可方便设置
- **Thread.MIN_PRIORITY = 1; 最小优先级**
- **Thread.MAX_PRIORITY = 10; 最大优先级**
- **Thread.NORM_PRIORITY = 5; 默认优先级(main方法)**
以下为测试代码,看java代码实际运行中的优先级效果。 代码表述为:分别创建两个线程,为两个线程设置优先级为1和10,同时开启线程,并同时打印当前线程名和线程优先级。
public class ThreadPrority {
public static void main(String[] args) throws JsonProcessingException {
System.out.println(Thread.currentThread().getName()
+"("+Thread.currentThread().getPriority()+ ")");
Thread t1=new MyThread("t1"); // 新建t1
Thread t2=new MyThread("t2"); // 新建t2
t1.setPriority(1); // 设置t1的优先级为1
t2.setPriority(10); // 设置t2的优先级为10
t1.start(); // 启动t1
t2.start(); // 启动t2
}
}
class MyThread extends Thread{
public MyThread(String name) {
super(name);
}
@SneakyThrows
public void run(){
for (int i=0; i<5; i++) {
System.out.println(Thread.currentThread().getName()
+"("+Thread.currentThread().getPriority()+ ")"
+", loop "+i);
}
// Thread.sleep(100000);
}
};
执行多次效果为:
为什么会导致这样呢,我们接下来来看一下setPriority的源码:
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();//这里是判断当前线程是有权限
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {//大于10或者小于1参数输入有误
throw new IllegalArgumentException();
}
//这里g是获得当前线程组,此时t1、t2的线程组都是main线程,这俩线程都是基于main线程创建出来的
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
//这里的意思是如果当前设置线程比线程组的最大线程优先级还要大,就设置成线程组的线程优先级
newPriority = g.getMaxPriority();
}
//native 操作系统设置优先级
setPriority0(priority = newPriority);
}
}
我们先在t1设置优先级时打个断点,debug如下:
setPriority 这个方法,他是 jvm 提供的一个方法,并且能够调用 本地方法 setPriority0. 我们发现优先级貌似没有起作用,为什么?
- 我们现在的计算机都是多核的,t1,t2 会让哪个cpu处理不好说。由不同的cpu同时提供资源执行。
- 优先级不代表先后顺序。哪怕你的优先级低,也是有可能先拿到我们的cpu时间片的,只不过这个时间片比高优先级的线程的时间片短(或者说是概率低)。 优先级针对的是 cpu时间片的长短问题。
- 目前工作中,实际项目里,不必要使用setPriority方法。我们现在都是用 hystrix, sential也好,一些开源的信号量控制工具,都能够实现线程资源的合理调度。这个 setPriority方法,很难控制。实际的运行环境太复杂。
但是需要注意:
默认情况下,一个线程会继承构造它的那个线程的优先级。(前面例子中的t1、t2都继承了main线程默认的5优先级,但是后来又重新设置了新的优先级)
每当线程调度器有机会选择新线程时,它首先选择具有较高优先级的线程。但是,线程的优先级高度依赖于系统。当虚拟机依赖于宿主机平台的线程实现时,Java线程的优先级会映射到宿主平台的优先级,平台的线程优先级别可能比Java的10个级别多,也可能更少。
例如,Windows有7个优先级别。Java的一些优先级会映射到同一个操作系统优先级。在Oracle为Linux提供的Java虚拟机中,会完全忽略线程优先级————所有线程都具有相同的优先级。
在没有使用操作系统线程的Java早期版本中,线程优先级可能很有用。不过现在不要使用线程优先级了。
(二)java守护线程
Daemon线程是一种支持型线程,因为它主要被用作程序中后台调度以及支持性工作。这意味着,当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会退出。可以通过调用Thread.setDaemon(true)将线程设置为Daemon线程。 代码演示如下:
我们可以看到,此时守护线程并没有执行整个程序就已经结束了,尤其是finally都没有执行,说明当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会退出
其中setDaemon()源码如下:
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {//如果当前线程是存活的则报错
throw new IllegalThreadStateException();
}
daemon = on;
}
isAlive(): 必须要先设置线程是否为守护线程,然后再调用start方法。如果你先调用start。