Java从诞生开始就选择了内置对多线程的支持,这使得Java语言相比同一时期的其他语言具有明显的优势。
线程作为操作系统调度的最小单元,多个线程能够同时执行,这将显著提升程序性能,在多核环境中表现的更加明显。
什么是线程呢?
- 现在操作系统在运行一个程序时,会为其创建一个进程。
- 现代操作系统调度的最小单元是线程,也叫轻量级进程。
- 在一个进程中可以创建多个线程,这些线程都拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。处理器在这些线程上高速切换,让人觉得这些线程在同时执行。
Java程序天生就是多线程程序,以代码为例:
package day20190104;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
public class MultiThread {
public static void main(String[] args) {
//获取Java管理MXBean
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
//获取线程和线程堆栈信息
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线程中,通过一个整型成员变量priority来控制优先级,优先级的范围从1~10,在线程构建的时候可以通过setPriority(int)方法来修改优先级,默认优先级是5,优先级越高分配到的时间片的数量越多。
设置线程优先级时,针对频繁阻塞(休眠或者I/O操作)的线程需要设置较高优先级,而偏重计算(需要较多CPU时间或偏运算)的线程则设置较低的优先级,确保处理器不会被独占。
在不同的JVM以及操作系统上,线程规划会存在差异,有些操作系统甚至会忽略对优先级的设定。
package day20190104;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class Priority {
private static volatile boolean notStart = true;
private static volatile boolean notEnd = true;
public static void main(String[] args) throws Exception {
List<Job> jobs = new ArrayList<Job>();
for(int i = 0; i < 10; i++) {
int priority = i < 5 ? Thread.MIN_PRIORITY : Thread.MAX_PRIORITY;
Job job = new Job(priority);
jobs.add(job);
Thread thread = new Thread(job, "Thread:" + i);
thread.setPriority(priority);
thread.start();
}
notStart = false;
TimeUnit.SECONDS.sleep(10);
notEnd = false;
for (Job job : jobs) {
System.out.println("Job Priority : " + job.priority + ",Count : " + job.jobCount);
}
}
static class Job implements Runnable {
private int priority;
private long jobCount;
public Job(int priority) {
this.priority = priority;
}
public void run() {
while (notStart) {
Thread.yield();
}
while (notEnd) {
Thread.yield();
jobCount++;
}
}
}
}
运行结果:
Job Priority : 1,Count : 255926
Job Priority : 1,Count : 255985
Job Priority : 1,Count : 255957
Job Priority : 1,Count : 255953
Job Priority : 1,Count : 255920
Job Priority : 10,Count : 2930794
Job Priority : 10,Count : 2923268
Job Priority : 10,Count : 2928370
Job Priority : 10,Count : 2923873
Job Priority : 10,Count : 2926149
/**
根据结果还是可以看出来优先级高的运行次数多,但是有些操作系统和JVM是存在不受优先级控制的情况的。
*/
线程的状态
Java线程在运行的生命周期可能处于一下六种不同状态,在给定的一个时刻,线程只能处于其中一个状态。
状态名称 | 说明 |
---|---|
NEW | 初始状态,线程被构建,但是还没有调用start()方法 |
RUNNABLE | 运行状态,Java线程将操作系统中的就绪和运行两种状态笼统地称作“运行中” |
BLOCKED | 阻塞状态,表示线程阻塞于锁 |
WAITING | 等待状态,表示线程进入等待状态,进入该状态表示当前线程需要等待其他线程做出一些特定动作(通知或中断) |
TIME_WAITING | 超时等待状态,该状态不同于WAITING,它是可以在指定的时间自行返回的 |
TERMINATED | 终止状态,表示当前线程已经执行完毕 |
线程在自身的生命周期中,并不是固定地处于某个状态,而是随着代码的执行在不同的状态之间进行切换。
Daemon线程
Daemon线程是一种支持型线程,因为它主要被用作程序中后台调度以及支持性工作。这意味着,当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会推出。
可以通过调用Thread.setDaemon(true)将线程设置为Daemon线程。