本文内容大部分来自动力节点课程学习,感兴趣的可以直接去看原视频课程。
用户线程和守护线程
Java语言中线程分为两大类:
- 用户线程:主线程main方法是一个用户线程
- 守护线程(后台线程):有代表性的是垃圾回收机制。一般守护线程是一个死循环,所有的用户线程只要结束,守护线程自动结束。
守护线程用在的地方?
- 每天00:00的时候系统数据自动备份,这个时候需要使用到定时器,并且可以将定时器设置为守护线程。所有的用户线程如果结束了,守护线程自动退出,没有必要进行数据备份了。
- 实际开发中,每隔多久执行一段特定的程序,这种需求很常见,在Java开发中其实可以采用多种方式实现
- 可以使用sleep方法,设置睡眠时间,这种是最原始的计时器
- 在Java类库中已经写好了一个定时器:java.util.Timer,可以直接拿来用,目前这种任务在目前的开发中也很少用,因为现在有很多高级框架都是支持定时任务的
- 实际开发中,目前使用较多的是Spring框架中提供的SpringTask,这个框架只要进行简单的配置,就可以完成定时器的任务
- 实际开发中,每隔多久执行一段特定的程序,这种需求很常见,在Java开发中其实可以采用多种方式实现
finally里面的语句一定会执行吗
一般情况下都会执行的,有两种特殊情况,不允许再执行final中的代码
-
使用System.exit来退出JVM
-
把当前执行try catch finally代码的线程设置为守护线程
-
原因:Java线程分为两类:守护线程和非守护线程。当所有的非守护线程中止时,无论是是否存在守护线程,JVM都会杀死守护线程从而中止程序。在JVM中,执行main方法的线程就是一个非守护线程,垃圾回收是一个守护线程,main执行完,程序就中止了,而不管垃圾回收线程是否中止。所以,如果守护线程中存在finally代码块,那么当所有的非守护线程中止时,守护线程被杀死,其finally代码块是不会执行的。
public class ThreadTest01 { public static void main(String[] args) { MyThread myThread = new MyThread(); Thread t = new Thread(myThread); // 设置为守护线程 t.setDaemon(true); t.setName("备份数据"); t.start(); // 主线程:用户线程 for(int i = 0; i < 10; i++){ System.out.println(Thread.currentThread().getName() + "--->" + i); try{ Thread.sleep(1000); }catch (InterruptedException e){ e.printStackTrace(); }finally { System.out.println("执行用户线程finally代码块" + i); } } } } class MyThread implements Runnable{ @Override public void run() { int i = 0; while(true){ System.out.println(Thread.currentThread().getName() + "--->" + (++i)); try{ Thread.sleep(1000); }catch (InterruptedException e){ e.printStackTrace(); }finally { System.out.println("执行守护线程finally代码块" + i); } } } }
上述代码的执行结果为:
main—>9
执行守护线程finally代码块10
备份数据—>11
执行用户线程finally代码块9当主线程执行完成,守护线程自动结束,守护线程中的finally代码块不再执行
-