多线程简介

线程概念

进程与线程

进程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;进程——资源分配的最小单位
线程:cpu的最小执行单位是线程
线程串行:归根结底就是单条线程来执行多个任务
线程并行:同一个时刻发生,并且在时间上是重叠的

进程与线程关系

  1. 一个线程只能属于一个进程,而一个进程可以有多个线程。(至少有一个线程)
  2. 资源分配给进程,同一进程的所有线程共享该进程的所有资源。同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)
  3. 处理机分给线程,即真正在处理机上运行的是线程
  4. 线程在执行过程中,需要协作同步。
    不同的线程要利用消息通信的办法实现同步

多线程使用场景

  1. 批量处理任务

向大量用户发送邮件 丨 处理大批量文件

  1. 实现异步

快速响应用户 丨 自动作业处理

  1. 增大吞吐量

tomcat 丨 数据库

总结使用场景特点 :逻辑之间无依赖关系,可同时执行,则可以应用多线程技术进行优化

线程组(ThreadGroup)

ThreadGroup的提出是为了方便线程的管理,通过它可以批量设定一定想成的属性,也可以通过线程组方便的获得线程的一些信息。

尽量不要使用,会带来线程安全问题

启动线程

new Thread().start();

执行逻辑

Runable
Callable<T>

Runable与Callable区别

  • 两者都是接口,Callable有call方法,Runable有run方法
  • Callable有返回值,Runable没有返回值
  • Callable返回值进行泛型化,创建时传递进去,执行结束后返回
  • Callable方法抛出异常,run方法无法抛出异常
  • Callable可以获取执行动态,中途取消。Runable无法获取执行状态

Runable与Callable联系

  • Runable 实例对象需要 Thread 包装类启动
  • Callable call 方法实际是在 Runable 的 run 方法中执行
  • Callable 先通过 FutureTask 方法包装成 Runable ,在交给 Thread 包装执行

终止线程

stop:可能导致线程安全问题,JDK不建议使用
destroy: JDK中删除方法
标志位:代码逻辑中增加一个标志位

线程守护

  • 守护线程
    当进程不存在或主线程停止,守护线程也会被停止
  • 用户线程
    指用户自定义创建的线程,主线程停止,用户线程不会停止

注意:

  1. thread.setDaemon(true)必须在thread.start()之前设置,否则会抛出一个IllegalThreadException异常,你不能把正在运行的常规线程设置为守护线程
  2. 在Daemon线程中产生的新线程也是Daemon的
  3. 守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断

线程状态

  1. NEW
    尚未启动的线程的线程状态
  2. RUNABLE
    可运行线程的线程状态,等待CPU调度
  3. BLOCKED
    线程等待状态 // 处于方法中被阻塞
  4. WAIT
    线程等待状态 // 不带Timeout参数的方式调用Object,wait,Thread join,LockSupport.park
  5. TIMED_WAITING
    具有指定等待时间的线程的线程状态 // 带超时的方式:
    Thread.sleep、Object.wait、Thread.join、LockSupport.parkNanos、LockSupport.parkUntil
  6. TERMINATED
    线程执行完毕,已经退出

interrupt

线程不会被中断

  • interrupt 不会中断线程,只是打上中断标记
  • 不会切断线程的状态
  • 只会改变 interrupt 的状态

在Waiting、Timed Waiting状态使用

wait()、wait(long)、join()、join(long,int)、join(long,int)、sleep(long,int)或sleep(long,int)等方法后
处于Waiting、Timed Waiting状态使用,该线程调用interrupt 方法后,线程的Waiting、Timed Waiting状态被消除,并抛出InterruptException异常

park()、parkNanos() 方法执行后

线程也处于Waiting、Timed Waiting,也会被唤醒,但是不会抛出异常,有时会出现挂起失效

目标是I/O或者NIO

如果目标线程是I/O 或者NIO中的Channel 所阻塞,同样I/O操作会被中断或者返回特殊异常值,达到终止线程的目的

终止线程

可以通过while循环 判断!Thread.currentThread().isInterrupted() 来达到终止线程的目的

线程间的通信方式

数据交互

  • 文件共享
  • 网络共享
  • 共享变量

线程协作

JDK中提供的协调API

  1. suspend / resume
    调用suspend挂起目标线程,通过resume可以恢复线程执行
    容易出现死锁
  • 死锁的suspend/resume。 suspend并不会像wait一样释放锁,故此容易写出死锁代码
  • 在Thread.sleep 使用时间不对等的时候 会永久性的挂起
  1. wait / notify (notifyAll)
    作用:
    wait方法导致当前线程等待,加入该对象的等待集合中,并且放弃当前持有的对象锁
    notify/notifyAll方法唤醒一个或所有正在等待这个对象锁的线程
    注意:
  • 虽然会wait自动解锁,但是对于顺序有要求,如果在notify被调用之后,才使用wait的调用,线程会永远处于waiting状态
  • 这些方法只能由同意对象锁的持有者线程调用,也就是在同步块里面,否则会抛出IllegalMonitorStateException异常
  1. park / unpark
    线程调用park则等待"许可",unpark 方法为指定线程提供"许可(permit)"
  • 调用unpark之后,再调用park,线程会直接运行
  • 提前调用unpark不叠加,连续多次嗲用unpark后,第一次调用park后后拿到"许可"直接运行,后续调用会进入等待

伪唤醒

是指线程并非因为notify、notifyall、unpark等api调用而意外唤醒
代码中用if句判断,是否进入等待状态,这样的做法是错误的

官方建议应该在循环中检查等待条件,原因是处于等待状态的线程可能会收到错误警报和伪唤醒,如果不在循环中检查等待,程序可能在没有满足条件结束的情况下退出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值