目录

「001」 Java 线程

从操作系统的层次上看,现代操作系统最重要的特性之一是多任务,区别于单道程序设计,先进的软硬件使得计算机能够看起来在同一时刻运行多个程序,这种能力叫做操作系统的并发性。 从程序设计的层次上看,单个程序同时完成多个任务的能力叫做程序的并发性。 并发性可以通过多进程和多线程实现,本质的区别在于每一个进程都有其独立的数据,进程间通信速度慢,创建一个进程的系统开销大,而线程共享父进程的数据,同一进程不同线程之间数据可以直接共享,线程间通信速度快,创建一个线程的系统开销小。相比于进程,线程更加“轻量化”。

进程是什么?

进程是程序运行的一次执行过程,是一个具有独立功能的程序在某个数据段上的一次活动,是计算机分配资源的最小单位

进程具有动态性、并发性、独立性和异步性的特点。

进程由代码段、数据段和堆栈段组成,Linux 通常将进程分为程序、数据和进程控制块,可以认为三者之间是一一对应的,堆栈段作为纽带,将代码和数据联系在一起。

线程是什么?

线程同样是程序运行的一次执行过程,是一个具有独立功能的程序在某个数据段上的一次活动,是处理器调度的最小单位

区别于进程,线程是进程的简化,一个进程可以拥有多个线程,多线程多处理机系统可以并行运行这些线程,同一进程的不同线程切换开销小,数据共享难度低。

Linux 系统中,线程就是特殊的进程。

线程有哪些状态?

线程状态图

线程有六种状态:

  • new 新建态
  • runnable 可运行态
  • blocked 阻塞态
  • waiting 等待态
  • timed waiting 计时等待态
  • terminated 终止态

线程创建后,还没有开始运行,此时线程处于新建态;

当线程启动后,线程处于可运行态,通知操作系统线程已就绪,等待处理机调度;

当资源不足、等待信号、超时时,将分别进入阻塞态、等待态和终止态;

当线程运行完成或意外结束时,将进入终止态。

线程有哪些属性?

线程名

线程名是线程的名称。构造一个线程对象时会默认为其分配一个线程名,如 Thread-2,可以用 setName 方法为其声明一个自定义的线程名。

线程优先级

线程优先级是 Java 虚拟机调度时何者第一何者第二调度的依据。默认情况下线程将会继承它的父线程的优先级,可以使用 setPriority 方法在 MIN_PRIORITY (定义为0)和 MAX_PRIORITY (定义为10)之间手动调整,NORM_PRIORITY 为5。

线程中断状态

除线程中的 run 方法执行体中执行完成并 return 返回正常退出,或出现未捕获的异常导致线程错误终止外,没有任何方法可以强制终止线程

除此之外,只有 interrupt 方法可以向系统发出请求终止的指令,更改线程的中断状态,检查中断后将线程转交给异常处理程序。

设计线程执行体时应当轮询中断状态,一旦检测到打开了中断状态就应当使用 return 语句安全退出线程进入中断处理程序段。

1
2
3
4
5
6
7
8
// open Interrupt State
Thread.currentThread().interrupt();

// check Interrupt State
Thread.currentThread().isInterrupted();

// check Interrupt State and clear it
Thread.interrupted();

被阻塞的线程无法检查中断状态。在被 sleepwait 阻塞的线程上调用 isInterrupted 方法不仅会清除中断状态,而且会抛出 InterruptedException 异常。

守护线程

守护线程是为其他线程提供服务的线程。可以在线程启动之前使用 setDaemon 方法将线程标记为守护线程,一旦虚拟机中只剩下守护线程时,虚拟机将退出,因为此时守护线程没有了服务对象,其本身又不能产生任何功能。

1
2
3
var t = new Thread(runnable);
t.setDaemon(true);
t.run();

未捕获异常的处理器

未捕获异常是可传播的非检查型异常,如数组下标越界等,通常会导致线程终止。在线程死亡前会将该异常传递给未捕获异常的处理器,默认处理器为 null,可自定义处理器,如定义一个使用日志 API 的处理器,将未捕获的异常发送到日志文件中。