线程优先级
- 线程优先级就是决定这个线程获得更多或者更少的处理器资源.
- 操作系统采用时分的方式来调度线程
- 给每个线程分配若干时间片,时间片用完了就切换另一个线程
- 时间片的多少就决定了线程用到的处理器资源的多少
- 线程优先级是线程的一个属性,通过setPriority()方法进行设置
- 线程优先级有1-10个等级,默认等级是5,优先级越高分配到的资源越多
- 对于频繁阻塞的线程(比如休眠、I/O操作等)一般需要更高的优先级,偏向计算的可以设置低优先级
- 在不同的JVM或操作系统中,优先级情况可能不同,甚至会被直接忽略(我们的修改不起作用)
线程状态(6种)
- NEW:初始状态,线程被构建,但是没有调用start方法
- RUNNABLE:运行状态,Java将操作系统中的就绪和运行统称为“运行中”
- BLOCKED:阻塞状态,表示线程阻塞于锁
- WAITING:等待状态,表示线程进入等待状态,进入该状态表示当前线程需要等待其他线程的动作(通知/中断)
- TIME_WAITING:超时等待,设置一个时间,超过这个时间就不等了,自行返回
- TERMINATED:终止状态,线程执行完毕
- 线程在声明周期中,不是固定在某个状态,而是随着代码的执行在不同状态之间切换
Daemon线程
- Daemon线程是后台线程,当Java虚拟机中没有非后台线程的时候,虚拟机就会退出
- Thread.setDaemon(true)将线程设置为Daemon线程
- 如果要设置,必须在线程启动之前
- 虚拟机退出时,所有后台线程会终止
- 后台线程中的finally语句块不一定执行,所以不能在finally中关闭或者清理资源。比如下面代码就没有任何输出
public class Priority {
public static void main(String[] args) {
Thread thread = new Thread(new DaemonRunner(), "DaemonThread");
thread.setDaemon(true);
thread.start();
}
static class DaemonRunner implements Runnable {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("DaemonThread finally run.");
}
}
}
}
启动终止一个线程
- 调用start方法,线程启动,run方法执行完毕,线程终止
构造线程
- 在Thread类源码中,构造一个线程对象会有一个对应的parent线程(就是父线程)进行空间分配
- child线程(子线程)会继承父线程的各种属性,比如是否为Dameon后台、优先级情况、和可继承的ThreadLocal等
- 会分配一个唯一ID标识子线程
- 线程对象创建完毕会放在堆内存
启动线程
- 调用start即可启动线程
中断线程
- 每个线程都有一个中断标识位
- 线程B可以调用线程A的interrupt方法来将线程A的中断标识设为true
- interrupt方法只会改变线程的中断状态,并不会真正中断线程,需要线程自己来决定中断还是不中断,但有可以中断线程的方法,如sleep,wait,join等,这些方法会不断的监测中断状态,一旦中断状态是true,就会立即中断线程,并抛出异常。如果抛出中断异常,说明线程已经中断。
- 线程可以通过isInterrupted()方法来判断线程是否已经中断
- 线程可以通过调用静态方法Thread.interrupted()方法来对标识位进行复原
- 一个线程终止后,无论有没有被中断过,调用这个线程的isInterrupted()都会返回false
- 线程方法在抛出InterruptException之前都会先清除中断标记位,然后才抛出异常
比如下面两个线程,sleep和busy线程,明明都被中断过,sleep抛出异常前清除了标记位
public static void main(String[] args)throws Exception {
Thread sleep=new Thread(new SleepRunner(),"sleepThread");
sleep.setDaemon(true);
Thread busy=new Thread(new BusyRunner(),"BusyThead");
busy.setDaemon(true);
sleep.start();
busy.start();
TimeUnit.SECONDS.sleep(5);
sleep.interrupt();
busy.interrupt();
System.out.println("sleep线程是否被中断过:"+sleep.isInterrupted());
System.out.println("busy线程是否被中断过:"+busy.isInterrupted());
TimeUnit.SECONDS.sleep(2);
}
static class SleepRunner implements Runnable{
@Override
public void run(){
while(true){
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class BusyRunner implements Runnable{
@Override
public void run(){
while(true){
}
}
}
sleep线程是否被中断过:false
busy线程是否被中断过:true
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at currentTest.Priority$SleepRunner.run(Priority.java:30)
at java.lang.Thread.run(Thread.java:748)
终止线程
- 终止线程有两个方法:调用该线程的interrupt方法、自己创建一个布尔变量控制线程
- 前者调用线程isInterrupted方法可以检测出来,而后者手动创建布尔变量的方式能终止线程,但是isInterrupted方法检测不出来
public static void main(String[] args) throws Exception{
Runner one =new Runner();
Runner two=new Runner();
Thread countThread=new Thread(one,"CountThread");
countThread.start();
//睡眠1秒 然后中断线程
TimeUnit.SECONDS.sleep(1);
countThread.interrupt();//main线程对countThread进行中断
System.out.println(countThread.isInterrupted()); //true
countThread=new Thread(two,"CountThread");
countThread.start();
TimeUnit.SECONDS.sleep(1);
two.Canle();
System.out.println(countThread.isInterrupted());
}
private static class Runner implements Runnable{
private long i;
private volatile boolean on=true;
@Override
public void run(){
while(on && !Thread.currentThread().isInterrupted()){
i++;
}
System.out.println("Count i="+i);
System.out.println("线程中止");
System.out.println(Thread.currentThread().isInterrupted());
}
public void Canle(){
System.out.println("下面修改标记变量进行中断");
on=false;
}
}
true
Count i=609041703
线程中止
true
下面修改标记变量进行中断
false
Count i=750220463
线程中止
false