深入并发-线程

线程的出现

什么是进程?

进程的本质是一个 正在执行的程序,程序运行时系统会创建一个进程,并且给每个进程分配独立的内存地址空间保证每个进程地址不会相互干扰。同时,在 CPU 对进程做时间片的切换时,保证进程切换过程中仍然要从进程切换之前运行的位置出开始执行。所以进程通常还会包括程序计数器、堆栈指针。

有了进程以后,为什么还会发明线程呢?

  1. 在多核 CPU 中,利用多线程可以实现真正意义上的并行执行
  2. 在一个应用进程中,会存在多个同时执行的任务。如果其中一个任务被阻塞,将会引起不依赖该任务的任务也被阻塞。通过对不同任务创建不同的线程去处理,可以提升程序处理的实时性
  3. 线程可以认为是轻量级的进程,所以线程的创建、销毁比进程更快、更节约资源

进程与线程的区别

  1. 一个进程可以包括多个线程, 一个线程只能属于一个进程
  2. 进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
  3. 进程之间是不共享资源,线程可与同属一个进程的其他的线程共享进程所拥有的全部资源
  4. 进程之间互不影响,一个线程死掉可能会导致整个进程挂掉从而导致其他线程也都死掉

线程的应用

如何创建线程

  1. 继承 Thread 类
  2. 实现 Runnable 接口
  3. 实现Callable接口
  4. 使用 ExecutorService
线程的生命周期

线程的生命周期包括6种状态

  1. NEW(初始状态):线程被构建,但是还没有调用 start 方法
  2. RUNNABLE(运行状态):将就绪状态和运行中状态统称为运行状态
    a. 就绪状态:启动了start()方法(处于可运行线程池中,等待被线程调度选中分配CPU时间片)
    b. 运行中状态:获得了CPU时间片就变成了运行中状态,指当前线程正在执行
  3. BLOCKED(阻塞状态):等待获取锁就会进入阻塞状态
  4. WAITING(等待状态):主动让线程进入睡眠,等待主动唤醒线程进入就绪状态(wait、join、park)
  5. TIMED_WAITING(超时等待):超时等待状态,超时以后达到一定时间后会自动唤醒线程(sleep、wait、join、parkNanos、parkUntil)
  6. TERMINATED(终止状态):表示当前线程执行完毕

在这里插入图片描述

如何查看线程状态

  1. 运行 java 程序,打开终端或者命令提示符,键入“jps”, (JDK1.5 提供的一个显示当前所有 java 进程 pid 的命令)
  2. 根据上一步骤获得的 pid,继续输入 jstack pid(jstack 是 java 虚拟机自带的一种堆栈跟踪工具。jstack 用于打印出给定的 java 进程 ID 或 core file 或远程调试服务的 Java 堆栈信息)

如何终止一个线程

  • 线程的终止并不是简单的调用 stop 命令。虽然 api 仍然可以调用,但是和其他的线程控制方法如 suspend、 resume 一样都是过期了的不建议使用。就拿 stop 来说, stop 方法在结束一个线程时并不会保证线程的资源正常释放,因此会导致程序可能出现一些不确定的状态。
  • 要优雅的去中断一个线程,在线程中提供了一个 interrupt 方法。当其他线程通过调用当前线程的 interrupt 方法,表示向当前线程打个招呼,告诉它可以中断线程的执行了,至于什么时候中断,取决于当前线程自己。线程通过检查自身是否被中断来进行相应,可以通过 isInterrupted()来判断是否被中断。 这种通过标识位或者中断操作的方式能够使线程在终止时有机会去清理资源,而不是武断地将线程停止,因此这种终止线程的做法显得更加安全和优雅。

线程复位

Thread.interrupted()是属于当前线程的,是当前线程对外界中断信号的一个响应,表示自己已经得到了中断信号, 但不会立刻中断自己。具体什么时候中断由自己决定,让外界知道在自身中断前,他的中断状态仍然是 false,这就是复位的原因。复位的方式有两种:

  1. 通过 Thread.interrupted 方法对线程中断标识进行复位
  2. 对抛出 InterruptedException 异常的方法,在 InterruptedException 抛出之前,JVM 会先把线程的中断标识位清除,然后才会抛出 InterruptedException

为什么 Object.wait、 Thread.sleep 和 Thread.join 都 会 抛 出 InterruptedException

  • 这些方法都属于阻塞方法,而阻塞方法的释放会取决于一些外部的事件。但是阻塞方法可能因为等不到外部的触发事件而导致无法终止,所以它允许一个线程请求自己来停止它正在做的事情。当一个方法抛出 InterruptedException 时,它是在告诉调用者如果执行该方法的线程被中断,它会尝试停止正在做的事情并且通过抛出 InterruptedException 表示提前返回
  • 所以这个异常的意思是表示一个阻塞被其他线程中断了。 然后由于线程调用了 interrupt()中断方法,那么Object.wait、Thread.sleep 等被阻塞的线程被唤醒以后会通过 is_interrupted 方法判断中断标识的状态变化,如果发现中断标识为 true,则先清除中断标识,然后抛出 InterruptedException
  • InterruptedException 异常的抛出并不意味着线程必须终止,而是提醒当前线程有中断的操作发生, 至于接下来怎么处理取决于线程本身,比如
    1. 直接捕获异常不做任何处理
    2. 将异常往外抛出
    3. 停止当前线程,并打印异常信息
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值