现代操作系统在运行一个程序时,会为其创建一个进程,而现代操作系统调度的最小单元是线程,也叫轻量级进程,在一个进程里面可以创建多个线程,这些线程都拥有各自的计数器,堆栈和局部变量等属性,并且能够访问共享的内存变量,处理器在这些线程上高速切换,让使用者感觉这些线程在同时执行。
线程的状态
Java线程在运行的生命周期中可能处于下表的6中不同的状态之一,在给定的一个时刻,线程只能处于其中一个状态。
状态名称 | 说 明 |
---|---|
NEW | 初始状态,线程被构建,但是还没有调用start()方法 |
RUNNABLE | 运行状态,Java线程将操作系统的就绪和运行两个状态统称为“运行中” |
BLOCKED | 阻塞状态,表示线程阻塞于锁 |
WAITING | 等待状态,表示线程进入等待状态,进入该状态表示当前线程需要等待 其他线程做出一些特定动作(通知或中断) |
TIME_WAITING | 超时等待状态,该状态不同于WAITING状态,它是可以在指定的时间自行 返回的 |
TERMINATED | 终止状态,表示当前线程已经执行完毕 |
上图可以看到,线程创建之后状态为NEW
,调用start()方法开始运行,此时状态为RUNNABLE
,当线程执行wait()方法之后,线程进入等待状态WAITING
。进入等待状态之后的线程需要依靠其他线程的通知才能返回到运行状态RUNNABLE
,而超时等待状态TIME_WAITING
相当于在等待状态的基础上增加了超时限制,也就是超时时间达到时将会返回到运行状态。当线程调用同步方法时,在没有获取到锁的情况下,线程将会进入到阻塞状态BLOCKED
。在线程执行完Runnable的run()方法之后不将会进入到终止状态TERMINATED
。
守护线程(Daemon线程):Daemon线程是一种支持型线程,因为它主要被作用于程序中后台调度以及支持性工作,这意味着,当一个Java虚拟机不存在非Daemon线程的时候,Java虚拟机将会退出。可以通过
Thread.setDaemon(true)
将线程设置为Daemon线程。Java虚拟机的垃圾回收器就是一个典型的Daemon线程。
构建线程的几种方式
大致可以分为四种方式,下面简单介绍一下这四种方式
继承Thread类
通过继承Thread类然后重写run方法的方式来创建线程,下面是该方式的实现代码:
public class ChildThread extends Thread {
@Override
public void run() {
System.out.println("ChildThread");
}
public static void main(String[] args) {
new ChildThread().start();
}
}
实现Runnable接口
通过实现Runnable接口,然后将实现类作为Thread类的构造函数的target参数创建线程,下面是该方式的实现代码:
public class ChildRunnable implements Runnable {
@Override
public void run() {
System.out.println("ChildRunnable");
}
public static void main(String[] args) {
new Thread(new ChildRunnable()).start();
}
}
通过Callable和FutureTask创建线程
- 创建Callable接口的实现类 ,并实现call方法
- 创建Callable实现类的实现,使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的call方法的返回值
- 使用FutureTask对象作为Thread对象的target创建并启动线程
- 调用FutureTask对象的get()来获取子线程执行结束的返回值
下面是该方式的实现代码:
public class ChildCallable implements Callable<Object> {
@Override
public Object call() throws Exception {
System.out.println("ChildCallable");
return new Object();
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Object> childCallable = new ChildCallable();
FutureTask<Object> futureTask = new FutureTask<>(childCallable);
Thread thread = new Thread(futureTask);
thread.start();
futureTask.get();
}
}
通过线程池的方式创建线程
- 创建Runnable接口的实现类,并实现run方法
- 通过Executors工具类创建线程池
- 循环创建Runnable实现类对象调用线程池的execute方法执行线程
下面是该方式的实现代码:
public class ChildThreadPool implements Runnable {
// 线程池大小
public static int POOL_SIZE = 5;
@Override
public void run() {
System.out.println("ChildThreadPool");
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(POOL_SIZE);
for (int i = 0; i < POOL_SIZE; i++) {
ChildThreadPool childThreadPool = new ChildThreadPool();
executorService.execute(childThreadPool);
}
//关闭线程池
executorService.shutdown();
}
}
以上部分代码参考CSDN-Mr_baci(多线程的几种实现方式)
网友评论