1、线程简介
1.1 什么是线程?
1)、现代操作系统在运行一个程序时,会为其创建一个进程。例如,启动一个Java程序,操作系统就会创建一个Java进程。现代操作系统调度的最小单元是线程,也叫轻量级进程(Light Weight Process)
2)、在一个进程里可以创建多个线程,这些线程都拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。处理器在这些线程上高速切换,让使用者感觉到这些线程在同时执行。
一个
Java
程序从
main()
方法开始
执
行,然后按照既定的代
码逻辑执
行,看似没有其他
线
程 参与,但实际
上
Java
程序天生就是多
线
程程序,因
为执
行
main()
方法的是一个名称
为
main
的
线程。
下面使用
JMX
来
查
看一个普通的
Java
程序包含哪些
线
程
public class MultiThread{
public static void main(String[] args) {
// 获取Java线程管理MXBean
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
// 不需要获取同步的monitor和synchronizer信息,仅获取线程和线程堆栈信息
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
// 遍历线程信息,仅打印线程ID和线程名称信息
for (ThreadInfo threadInfo : threadInfos) {
System.out.println("[" + threadInfo.getThreadId() + "] " + threadInfo. getThreadName());
}
}
}
输出:
[4] Signal Dispatcher // 分发处理发送给JVM信号的线程
[3] Finalizer // 调用对象finalize方法的线程
[2] Reference Handler // 清除Reference的线程
[1] main // main线程,用户程序入口
可以看到,一个
Java
程序的运行不
仅仅
是
main()
方法的运行,而是
main
线
程和多个其他
线程的同时
运行
1.2 为什么要使用多线程
使用多线程原因主要有以下几点:
(
1
)更多的
处
理器核心
线
程是大多数操作系
统调
度的基本
单
元,一个程序作
为
一个
进
程来运行,程序运行
过
程中能够创
建多个
线
程,而一个
线
程在一个
时
刻只能运行在一个
处理器核心上。如果该程序使用多线程技术,将计算逻辑分配到多个处理器核心上,就会显著减少程序的处理时间,并且随着更多处理器核心的加入而变得更有效率。
(
2
)更快的响
应时间
使用多
线
程技
术
,即将数据一致性不
强
的操作派
发给
其他
线
程
理(也可以使用消息队
列),如生成
订单
快照、
发
送
邮
件等。
这样
做的好
处
是响
应
用
户请
求的
线 程能够
尽可能快地
处
理完成,
缩
短了响
应时间
,提升了用
户
体
验。
(
3
)更好的
编
程模型
Java
为
多
线
程
编
程提供了良好、考究并且一致的
编
程模型,使开
发
人
员
能
够
更加
专
注于
问 题的解决,即
为
所遇到的
问题
建立合适的模型,而不是
绞
尽
脑
汁地考
虑
如何将其多
线
程化。一旦开发
人
员
建立好了模型,稍做修改
总
是能
够
方便地映射到
Java
提供的多
线
程
编
程模型上。
1.3 线程优先级
在
Java
线
程中,通
过
一个整型成
员变
量
priority
来控制
优
先
级
,
优
先
级
的范
围
从
1~10
,在
线程构建的时
候可以通
过
setPriority(int)
方法来修改
优
先
级
,默
认优
先
级
是
5
,
优
先
级
高的
线
程分 配时间
片的数量要多于
优
先
级
低的
线
程。
设
置
线
程
优
先
级时
,
针对频
繁阻塞(休眠或者
I/O
操作)的线
程需要
设
置
较
高
优
先
级
,而偏重
计
算(需要
较
多
CPU
时间
或者偏运算)的
线
程
则设
置
较低的优
先
级
,确保
处
理器不会被独占。在不同的
JVM
以及操作系
统
上,
线
程
规
划会存在差异, 有些操作系统
甚至会忽略
对线
程
优
先
级
的
设
定。
1.4 线程的状态
1、NEW(初始状态):线程被构建,但是还没有调用start()方法。
2、RUNNABLE(运行状态):Java线程将操作系统中的就绪和运行状态称作”运行中“。
3、BLOCKED(阻塞状态):表示线程阻塞于锁。
4、WAITING(等待状态):表示线程进入等待状态。需要其他线程通知或中断。
5、TIME_WAITING(超时等待状态):该状态不同于WAITING,它是可以在指定的时间返回的。
6、TERMINATED(终止状态):表示该线程已经执行完毕。
1.5 Daemon线程
Daemon线程是一种支持型线程,因为它主要被用作程序中后台调度以及支持性工作。这
意味着,当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会退出。可以通过调
用Thread.setDaemon(true)将线程设置为Daemon线程。
注意: Daemon属性需要在启动线程之前设置,不能在启动线程之后设置
Daemon
线
程被用作完成支持性工作,但是在
Java
虚
拟
机退出
时
Daemon
线
程中的
finally
块并不一定会执
行。如下代码:
public class Daemon {
public static void main(String[] args) {
Thread thread = new Thread(new DaemonRunner(), "DaemonRunner");
thread.setDaemon(true);
thread.start();
}
static class DaemonRunner implements Runnable {
@Override
public void run() {
try {
SleepUtils.second(10);
} finally {
System.out.println("DaemonThread finally run.");
}
}
}
}
运行
Daemon
程序,可以看到在
终
端或者命令提示符上没有任何
输
出。
main
线
程(非 Daemon线
程)在启
动
了
线
DaemonRunner
之后随着
main
方法
执
行完
毕
而
终
止,而此
时
Java
虚
拟机中已经
没有非
Daemon
线
程,虚
拟
机需要退出。
Java
虚
拟
机中的所有
Daemon
线
程都需要立即 终止,因此
DaemonRunner
立即
终
止,但是
DaemonRunner
中的
finally
块
并没有
执
行。
注意:在构建Daemon线程时,不能依靠finally块中的内容来确保执行关闭或清理资源的逻辑。