初始线程Ⅲ之死锁问题

17 篇文章 0 订阅

回顾

多线程:

创建方式

  • 继承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

死锁关键代码

synchronized(lockA) {
	Thread.sleep(1000);
	synchronized(lockA) {
	//...
	}
}

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

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

如何解决死锁的问题

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

请求拥有条件:

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

线程通讯机制

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

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

wait为什么要加锁:

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

wait为什么要释放锁:

  • wait默认是不传任何值的,表示永久等待,造成一把锁被一个线程一直持有,避免这种问题发生,所以在使用wait是必须释放锁
注意
  1. 使用以上方法时,必须加锁
  2. 加锁 对象和wait 、notify / notifyAll 对象 必须保持一致
  3. 一组wait 、notify / notifyAll必须是同一个对象
  4. notifyAll只能唤醒当前对象的所以等待线程
区别
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注意:

System.out.println("线程进入休眠:" + new Date());
LockSupport.parkUntil(System.currentTimeMillis()+1000);
System.out.println("线程终止休眠:" + new Date());
wait VS LockSupport
waitLockSupport
可以让线程休眠可以让线程休眠
可以传参或不传参,且线程状态一致可以传参或不传参,且线程状态一致
需要配合synchronized一起使用(加锁)不需要加锁
只能唤醒全部或随机的一个线程可以唤醒指定的线程
来自Object的方法来自专门一个唤醒线程的类
  • wait(long):void -> 毫秒级别的最大等待时间
  • wait(long,int):void -> 纳秒级别的最大等待时间
  • wait():void -> 永久等待

为什么wait会放到Object中而不是Thread?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值