初始线程Ⅲ之死锁问题

文章目录

  • 回顾
    • 创建方式
    • 常见方法和属性
    • 特性
    • 状态
    • 线程安全问题
      • 线程不安全的五个因素
      • 线程不安全解决方案
  • 死锁
    • 查看死锁软件
    • 死锁关键代码
    • 形成死锁必须同时满足的条件
    • 如何解决死锁的问题
      • 线程通讯机制
        • 注意
        • 区别
          • Thread.sleep(0) VS Object.lock(0)
          • sleep() VS wait()
        • LockSupport
          • wait VS LockSupport

回顾

多线程:

创建方式

  • 继承Thread
  • 实现Runnable接口
  • 实现Callable接口

常见方法和属性

  • start()
  • run()
  • sleep():休眠
  • join():等待线程执行完成
  • interrupt():中止
  • yield() :让出CPU执行权
  • wait()
  • notfiy()
  • notfiyAll()

特性

  • 优先级
  • 线程分组

状态

初始线程Ⅲ之死锁问题

线程安全问题

线程不安全的五个因素

  1. CPU抢占式执行
  2. 内存可见性(volatile)
  3. 指令重排序
  4. 原子性
  5. 多个线程同时修改同一个变量

线程不安全解决方案

  1. 加锁,让多线程排队执行
  2. 使用私有变量

  1. synchronized
  2. lock

synchronized 、lock 、volatile区别

死锁

在多线程(两个或两个以上)中因为资源抢占而造成的无限等待问题

一个线程可以拥有多把锁
一把锁只能被一个线程拥有

查看死锁软件

  1. jconsole
  2. jvisualvm
  3. jmc

死锁关键代码

形成死锁必须同时满足的条件

  • 互斥条件:一个资源只能被一个线程持有(不可修改)
  • 请求拥有条件:一个线程持有一个资源后,又试图请求另一个资源(可修改)
  • 不可剥夺条件:一个资源被一个线程拥有之后,线程若不释放此资源,那么其他线程不能强制获得此资源(不可修改)
  • 环路等待条件:多个线程在获取资源时,形成一个环形链条(可修改)

如何解决死锁的问题

修改以下任意一个:
环路等待条件(容易实现):通过控制获取锁的顺序解决(按序请求锁)

请求拥有条件:

sleep休眠缺失:必须传递一个明确的结束数据

线程通讯机制

一个线程的动作可以被另一个线程感知

  • wait 休眠
  • notify 唤醒
  • notifyAll 唤醒全部

wait为什么要加锁:

  • wait在使用时,必须要释放锁,在释放锁之前必须要有一把锁,所以要加锁

wait为什么要释放锁:

  • wait默认是不传任何值的,表示永久等待,造成一把锁被一个线程一直持有,避免这种问题发生,所以在使用wait是必须释放锁

注意

  1. 使用以上方法时,必须加锁
  2. 加锁 对象和 对象 必须保持一致
  3. 一组必须是同一个对象
  4. 只能唤醒当前对象的所以等待线程

区别

Thread.sleep(0) VS Object.lock(0)
Thread.sleep(0) Object.lock(0)
Thread的静态方法 Object的方法
sleep(0)立即触发一次CPU的资源抢占 lock(0)永久等待
sleep() VS wait()
sleep() wait()
可以让当前线程休眠 可以让当前线程休眠
必须处理一个Interrupt异常 必须处理一个Interrupt异常
来自Thread的静态方法 来自Object的方法
必须要有一个>=0的参数 可以没有参数
不用加锁 必须加锁
不会释放锁 会释放锁
默认不传参情况会进入TIMED_WAITING状态 默认不传参情况会进入WAITING状态

LockSupport

  • part()
  • unpart()

LockSupport注意:

wait VS LockSupport
wait LockSupport
可以让线程休眠 可以让线程休眠
可以传参或不传参,且线程状态一致 可以传参或不传参,且线程状态一致
需要配合synchronized一起使用(加锁) 不需要加锁
只能唤醒全部或随机的一个线程 可以唤醒指定的线程
来自Object的方法 来自专门一个唤醒线程的类
  • -> 毫秒级别的最大等待时间
  • -> 纳秒级别的最大等待时间
  • -> 永久等待

为什么wait会放到Object中而不是Thread/p>

  • wait操作必须要加锁和释放锁,而锁是属于对象级别而不是线程级别(线程和锁是一对多的关系,一个线程会拥有多把锁),为了灵活起见,就将wait会放到Object中

文章知识点与官方知识档案匹配,可进一步学习相关知识Java技能树Java异步任务线程与进程91673 人正在系统学习中

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年4月8日
下一篇 2021年4月8日

相关推荐