Java线程简介
2018-05-08 本文已影响0人
Lebens
主要是介绍一些线程相关的知识点,包括线程的生命周期,守护线程等,为后续的博客做一些铺垫。
什么是线程
关于什么是线程,网上一大堆的介绍:
相对于进程,线程是操作系统(OS)调度的最小执行单元
线程的特点,根据线程的官方介绍可以看出:
- java应用可以同时执行多个线程
- 每个线程都有优先级,优先级高的线程优先于低优先级的线程执行
- 线程在创建时可以设置为守护线程
- 虚拟机启动时会有一个非守护线程的,也就是main方法所在的线程
- 当一个应用程序所有的非守护线程死亡时,jvm退出,同时所有守护线程被销毁
- 线程的创建有2种方式:继承Thread类并覆写run方法;在构造时传入一个Runnable实现类参数
- 每个线程都有一个名字用于标识线程
几个点需要说一下:
- 当设置一个线程为守护线程时,只能在调用Start()方法前设置,否则抛出异常
- 线程优先级分为1-10,默认为5
- 死亡的线程无法再次被运行
线程的生命周期
线程的生命周期分为新建状态、就绪状态、运行状态、阻塞状态 和 死亡状态 5种状态,这5种状态的转换如下图所示:
线程生命周期图.jpeg- 调用new关键字,新建一个Thread实例对象有,实例对象就处于新建状态。
- 当Thread实例对象调用start()后,进入就绪状态可以被cpu调度执行。
- 就绪状态的Thread实例对象,在获取到cpu执行权后就可以运行。同时由于cpu的切换或者调用了线程的yield方法,会导致运行状态的Thread回到就绪状态。
- 当运行状态的线程遇到如下几种情况时将进入阻塞状态
- wait()
- sleep()
- join()
- 等待同步锁
- 阻塞式I/O调用
- 阻塞状态的线程恢复进入就绪状态,当然在阻塞时线程被中断,那么线程进入死亡状态。
- 运行状态的线程正常运行完毕或者中断异常都将进入死亡状态。
守护线程
相对于正常线程,也就是所谓的用户线程来说,守护线程主要是用于为用户线程提供便利,这也是守护这个词的含义,最典型的就是java系统的GC线程。
当所有用户线程退出时,守护线程就没有服务对象也没有存在的意义,所以随着jvm的退出,所有的守护线程都会被销毁,这也就是java文档的说明。
关于守护线程有如下几个注意点:
- 设置守护线程必须在线程start()之前
- 守护线程里执行的代码存在不完整执行的风险,所以涉及到数据计算保存的,需要有明确结果的操作不宜放在这里执行
- 在守护线程下新建的线程也为守护线程
关于第一点限制也很好理解,当你把启动的用户线程设置为守护线程时,可能刚好把唯一的用户线程消灭了,然后jvm退出了,导致了第二点的问题。
举个例子验证一下上面说的,所有用户线程退出后jvm退出导致守护线程销毁的说法:
public class ThreadTest {
public static void main(String[] args) {
try {
Thread thread = new Thread() {
@Override
public void run() {
try {
int i = 0;
while (true) {
System.out.println(i++);
Thread.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.setDaemon(true);
thread.start();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
打印结果如下:
0
1
2
3
4
Process finished with exit code 0
结果也很明显,每200毫秒打印一个数字,等主线程sleep结束就退出了。
如果把thread.setDaemon(true);注释调可以看到,线程一直会打印到底。
总结
- 线程有5种状态:新建状态、就绪状态、运行状态、阻塞状态 和 死亡状态
- 线程有2种创建方式
- 线程有优先级
- 线程有名字
- 守护线程需要在start()之前指定
- 守护线程代码可能执行不完整
- 守护线程下新建的都是守护线程