Java线程基础
创建线程的多种方式
- 继承thread类
- 实现Runnable接口
- 实现callable接口
- 使用executor框架实现线程池
线程的状态
- 新建状态
当一个Thread类或者其子类的对象被声明或者是创建,但没有执行的这段状态称为新建状态。
- 就绪状态
就绪状态也称为可运行状态。处于新建状态的线程被启动后,将进入线程列队排队等候cpu的调度,此时具备了运行的条件,也就是就绪状态。
- 运行状态
就绪状态的线程获得cpu的调度并获得系统资源后便进入了运行状态。
处于运行状态的线程在一下情况下将让出cpu的控制权
●线程运行完毕。
●有比当前优先级更高的线程处于就绪状态。
●线程主动睡眠一段时间。
●线程正在等待某一资源。
- 阻塞状态
一个运行的线程在某些特殊的情况下将让出cpu,并暂时中止自己的执行。线程处于这种不可运行的状态称为阻塞状态。下面几种情况下可以使一个线程进入阻塞状态。
●调用sleep()或者yield()方法。
●等待一个条件变量线程调用wait()方法。
●该线程与另一个线程join()在一起。
一个线程被阻塞时不能进入排队队列,阻塞的原因被消除时才能进入就绪状态。阻塞状态的线程通常需要某些事件才能唤醒,睡眠状态的线程必须阻塞一段固定时间。
- 消亡状态
处于消亡状态的线程不具备继续执行的能力,导致线程消亡的原因有两个:一是执行了run()方法的最后一条语句,二是进程中的线程被强制终止。
线程的调度与优先级:java语言支持抢占调度模型,每个线程都被赋予一个执行的优先级。从1到10整数型。Thread类有三个优先级的静态变量MIN_PRIORITY(1),MAX_PRIORITY(10),NORM_PRIORITY(5)。
User Thread(用户线程) vs Daemon Thread(守护线程)
java中有两类线程,分别是用户线程和守护线程只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
守护线程的存在主要是为其他线程提供服务,GC(垃圾回收)线程就是一个典例的守护线程。
用法上两者并没有什么区别,唯一区别是jvm结束时的区别:jvm要等所有用户线程结束掉后才会离开,而不用等待守护线程,守护线程随着jvm的结束而结束(当然守护线程任务完成后也会结束)
使用场景
- 消息推送线程
- 资源监控等
使用方法
Thread daemonTread = new Thread();
daemonThread.setDaemon(true);
daemonThread.start();
User Thread 和 Daemon Thread 使用注意点
- 守护线程要在
start()
方法调用之前调用setDaemon(true)
来把线程设置为守护线程,否者会抛出IllegalThreadStateException异常。 - 守护线程新建的线程默认也是守护线程,当然用户线程新建的线程默认也是用户线程。(主要参考Thread的init方法)
- 用户线程线程可以创建守护线程,当然守护线程也可以创建用户线程。
- 不要把业务类的或计算类等重要流程放到守护线程中去,因为在jvm计算时若计算未完成则也会结束掉守护线程。
- 不要随便使用用户线程。如在Web容器启动时启动Timer,当Web容器关闭时,除非你手工关闭这个Timer,否则Timer中的任务还会继续运行!