并发理解 part2

实现线程有几种方法

在这里插入图片描述
在这里插入图片描述

两种方法对比:
在这里插入图片描述
1 代码架构角度,代码任务应该和Thread类解耦,不应该混为一滩。
2 使用Runnable,利用后续线程池,大大减少线程损耗,继承Thread类执行任务,有线程创建,销毁等损耗
3 继承Thread 类 ,因为不能继承其他类,大大限制可扩展性

两种方法本质区别:
Thrad run方法是怎么写的 ,
在这里插入图片描述
target其实也是一个runnable,在构造函数时候传入,
在这里插入图片描述
在这里插入图片描述
方法一 是直接调用传入target的run方法。
方法二 是整个都被重写了。

思考题: 同时用两种方法会怎么样?
在这里插入图片描述
第二个run 覆盖了Thread里面的三行run方法,即使传入了Runable方法, 但已经被覆盖了,所以 Runable里面的run 不可执行。

在这里插入图片描述
错误理解:

线程池 为什么不是 创建线程的另一种方式?
因为线程池本质还是通过 ThreadFactory 基本都是DefaultThreadFactory创建Thread,只不过传入参数更多了。
在这里插入图片描述

通过Callable和FutureTask创建线程,也算一种新建线程的方式?
在这里插入图片描述在这里插入图片描述
定时器观点?
在这里插入图片描述
本质还是 那两类方法
在这里插入图片描述
在这里插入图片描述

这两种连类的包装都没有,其实只是语法层面的包装。其实停留在表现,都是实现方式。

在这里插入图片描述
本质要说,其他随意。
其他方式看源码都没有逃脱其他方式。

在这里插入图片描述

启动线程

start方法含义
调用start方法,不代表立刻运行,要有线程调度器去决定什么时候去运行。

start方法启动两次
在这里插入图片描述

一个线程两次调用start()方法会出现什么情况?为什么?
会抛出异常,以为在启动start方法时候,回去检查线程状态,如果是不符合标准的状态,将会抛出异常
在这里插入图片描述
看源码:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

为什么调用start方法,而不是直接执行run方法啊?

在这里插入图片描述
调用start方法才是真正意义上启动了一个线程,经历线程的各个声明周期,run就是执行一个普通方法

停止线程

如何正确停止线程
在这里插入图片描述
java没有停止线程的机制,只有使用interrupt这种合作机制,interrupt 是中断,不是停止,在Java中最多能做的就是中断,交给线程决定停止。但是线程自己不想中断,咱门无能为力,把停止线程,交给执行线程的本身。

其实这个问题,就是如何使用interrupt 进行通知,其他线程如何配合,这个就是核心

停止线程的最佳实践
1 run方法完毕了
2 线程有异常出现,又没有处理 就停止了

停止了,资源就会被JVM回收。
在这里插入图片描述
通常情况下,如何停止线程
在这里插入图片描述
直接调用interrupted 不会中断
在这里插入图片描述
需要配合才能停止,有效果,在1秒室内推断在这里插入图片描述
在sleep中阻塞,进行中断,会抛出异常InterruptedException。
在这里插入图片描述
这时候需要捕获异常,响应中断
在这里插入图片描述
是否还需要isInterrupted这个判断,大部分时间是会消耗在sleep(10)之中,所以这个判断是多余的。所以还是会抛出异常,
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
内try catch, sleep函数是native 方法,一旦响应中断,便会把Sleep标记位清除,再查就查不到了,也就是说,响应中断了,但是由于设计理念,标记位会被清除。看源码OpenJDK。
所以检查不到任何中断迹象。

处理终端最佳实践
在这里插入图片描述

传递中断:
在这里插入图片描述
这个处理是最应该选择的,这样做,在run方法中会强制trycatch

在这里插入图片描述
这个方法是别人写的,自己只是调用,就是坑。
在这里插入图片描述
在方法中把中断给吞了。没有上报,无法做出更多的处理,方法编写人有问题。
应该添加签名,强制在run方法中进行trycatch,run方法无法再次抛出了。
在这里插入图片描述
在这里插入图片描述
在这里可以感知中断,正确去处理这个中断。按照自己的思路进行相应。

恢复中断思路:
在catch子语句中调用Thrad.currentThread().intrrupt()来恢复设置中断状态,以便在后续执行中,依然能够检查到刚刚发生了中断。
在这里插入图片描述
在这里插入图片描述
在run方法中 在进行处理,无抛出异常,无法进行trycatch ,但是可以自己判断处理

在这里插入图片描述
最不应该做的就是屏蔽异常。

相应中断的方法列表:
有相应中断的能力,这些方法,将线程陷入阻塞,可以用interrupt方法中断线程
在这里插入图片描述在这里插入图片描述

为什么要用Interrupt?
被相应的线程,有能力自己处理线程逻辑,更加安全,并完成了清理,数据完整性得到了保障

错误停止线程的方式:
在这里插入图片描述
stop方法会释放掉所有的monitor,有些说法是错误的,看官网
在这里插入图片描述
suspend 不会释放锁,是带着锁去休息的,容易造成死锁。

volatile 是不行的:
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
看着好像挺好的,确实停止了。
但是有些时候是有问题的。
在这里插入图片描述在这里插入图片描述
100的倍数会放入队列。在这里插入图片描述
消费者:
在这里插入图片描述
主函数:
在这里插入图片描述

在这里插入图片描述
原因就是,阻塞队列java设计者设计的时候是可以相应中断的,你们用野方法,当然不行。
在这里插入图片描述
在这里插入图片描述
停止线程 重要方法 源码解析

以及其他判断线程是否中断的方法
在这里插入图片描述
在这里插入图片描述
gitHub 去看openJDK

在这里插入图片描述
另一个interrupted方法:
在这里插入图片描述
返回之后,清除了线程中断状态

在这里插入图片描述
这个方法不清楚 中断转态。
在这里插入图片描述

Java 异常体系

在这里插入图片描述
runtime Exception一定是程序员的问题。

生命周期

在这里插入图片描述
在这里插入图片描述
线程的生命周期是什么–参考答案就是这幅图

Thread 和Object 类中线程相关方法

在这里插入图片描述
在这里插入图片描述

线程优先级、4个属性总结、线程属性面试问题

在这里插入图片描述
在这里插入图片描述
通常不同设置守护线程。
不应该设置线程优先级,来帮助程序运行。

线程异常处理

异常体系图很重要,要看下
try catch 只能捕获对应线程内的异常

解决方法:
在这里插入图片描述
检测出线程里面出现的异常,并进行相关处理
在这里插入图片描述
这个接口是Thread类里面的一个接口
在这里插入图片描述
三种方法可以做这件事情:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
处理线程问题, 进行特殊处理,比如通知管理员,进行管理。

JMM

在这里插入图片描述
Java 内存模型
1 起因,多核情况下 表现不一致
2 一组规范,jvm ,cpu,java代码,帮助开发者 容易开发
3 重排序,可见性,原子性(例子,好处,可见性抽象图,happens-before,votaile,sync 以及两者关系,原子性,哪些操作原子性)
在这里插入图片描述
在这里插入图片描述
商用JVM 上 没有这个问题,32位操作系统不是,64位是,

死锁问题解决方案

在这里插入图片描述
在这里插入图片描述
因为锁只能被一个线程所获取,所以会死锁
在这里插入图片描述
在这里插入图片描述
死锁的影响
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
结束死锁时候看下退出信号,不是0,而是别的信号
在这里插入图片描述
实际工作情况中发生的问题: 银行转账问题
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
假设程序通讯有间隙
在这里插入图片描述
这回控制台什么都不打印了,都卡在了sync,正是因为 transferMoney 是 from to 在不同线程里面是相反的

500人随机转账,依然会发生死锁;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述因为是随机的,所以你转给我,我转给你的概率很小了。但结果还是会有死锁发生。

在这里插入图片描述
死锁发生的四个必要条件:

最好一个线程一把锁
数据库就是靠剥夺条件,来解决死锁的
在这里插入图片描述
要构成环路,才不可以解开。
就比如之前的必然死锁例子,o1 不能被多个线程同时拥有
请求o2 的时候 保持o1 满足第二个条件
没有人去剥夺

如何定位死锁:
Jps 命令行查询 ThreadId
在这里插入图片描述
在这里插入图片描述
很轻易的分析出来了呀,但如果死锁不明显,也可以帮咱们分析下线程栈持有那些锁,也能很好分析的。

在这里插入图片描述
在这里插入图片描述

这就找到了呀,互相等待的关系,多个线程都是相对等待的关系啊。

用代码方式解决问题

在这里插入图片描述
在未来经常会用锁的地方,加上这种保护,无论什么机制,及时发现,及时解决

如何修复死锁问题

在这里插入图片描述
不可预料,蔓延快,破坏性大
在这里插入图片描述
在这里插入图片描述
几个月几年才发生一次,就可以先不考虑了。
在这里插入图片描述
要想清楚意见事情

在这里插入图片描述
冲突时候要有加时赛。引入一把新锁,总有人会先抢到。
在这里插入图片描述
在这里插入图片描述

对于转账进行修改

在实际开发过程中,使用主键来获取高低顺序

哲学家就餐问题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解决哲学家问题的方法:
在这里插入图片描述
领导调节,有一个领导巡视,如果看到哲学家不行,就命令不许吃,创造剥夺条件。

在这里插入图片描述
在这里插入图片描述
死锁恢复机制:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
有可能哲学家特别老实,每次都放下,就会饿死。

实际开发中 避免死锁

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
死锁化解了,锁释放了,这么线程1,2 就成功获取了。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
降低锁的使用粒度,用不同的锁而不是一个锁,降低临界区。
在这里插入图片描述
自己制定锁对象,就有个控制权
在这里插入图片描述

命名的重要性
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
不同功能用不同的锁对象,而不是很多功能都用一个锁对象。

活锁

在这里插入图片描述
在这里插入图片描述
等待时间变为随机数,在进行放下
活锁消耗CPU 资源

如何解决活锁问题:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
不停的重试,导致整个程序无法运行。
在这里插入图片描述
Msg 不一定放到头部,重试限制,因为Msg 可能是个毒瘤,耗尽资源。

饥饿
在这里插入图片描述
在这里插入图片描述
优先级复习,编程不应该依赖优先级
在这里插入图片描述

避免方式:
1 编程的时候,不应该使用线程优先级这个概念。
2 编程不应该有锁不释放情况发生。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值