并发编程知识笔记

并发编程知识笔记

并行与并发

  • 并行:单位时间内,多个处理器或多核处理器同时处理多个任务,是真正意义上的"同时进行"。
  • 并发:多个任务在同一个CPU核上,按细分的时间片轮流执行,从逻辑上来看那些任务是同时执行。

守护线程和用户线程

  • 用户 (User) 线程:运行在前台,执行具体的任务,如程序的主线程、连接网络的子线程等都是用
    户线程

  • 守护 (Daemon) 线程:运行在后台,为其他前台线程服务。也可以说守护线程是 JVM 中非守护线
    程的 “佣人”。一旦所有用户线程都结束运行,守护线程会随 JVM 一起结束工作

进程、线程、纤程(协程)

进程

在内存中开辟一块空间,存储着应用程序的指令和数据。进程就是应用程序启动之后,放入内存中的内容。进程是资源分配的基本单位

线程

线程是程序执行的基本单位

纤程(协程)

协程是一种用户态的轻量级线程,协程的调度完全由用户控制,协程间切换只需要保存任务的上下文,没有内核的开销,不需要操作系统内核态和用户态之间的转换。

java内存模型(JMM) 与 volatile

传送门:
https://blog.csdn.net/weixin_40955398/article/details/122711070

概念

锁是一个逻辑概念,是为了保证数据的一致性,必要的采取的一些手段。

轻量级锁的效率一定比重量级锁的效率要高么?
不是,如果持有锁的线程释放锁很快、锁竞争不激烈,轻量级锁效率高,因为不用经过操作系统。
如果持有锁的线程执行时间很长、锁竞争超级激烈,10000个线程在等待,由于while循环是需要消耗cpu资源的,cpu会把大量资源消耗在线程切换上了,此时,重量级锁的效率要高于轻量级锁。

锁的四种状态

1、new,刚new出来,没有锁的状态
2、偏向锁状态
3、轻量级锁的状态
4、重量级锁的状态

synchronized

在jdk1.0~1.2,这个关键字直接使用重量级锁。是os将线程之间锁竞争、锁信息,告诉jvm,jvm才能继续执行。
在jdk后续版本中,陆续对synchronized关键字进行了优化,不再直接使用重量级锁。
针对于用户空间的锁,jdk1.5之后,推出了JUC的各种锁(都是CAS的实现)。

synchronized的锁升级

在这里插入图片描述
只要有锁竞争(其他线程抢锁),就开始第一次锁升级,由偏向锁升级为轻量级锁(自旋锁)。当自旋锁旋转到一定的次数或者线程数大于CPU最大可接待的线程数,开始第二次锁升级,线程进入队列,由轻量级锁升级为重量级锁。

偏向锁:
严格意义讲不是一种锁,它比轻量级锁还要轻。
偏向锁不用抢,它偏向于第一个线程。

无锁 —> 一种概念 指的是没有重量级锁,CAS、偏向锁都属于无锁


自旋锁(CAS CompareAndSwap)

CAS是自旋锁的实现方式,无需操作系统调度,在用户空间就可以解决。
原理: 开始从内存中读取当前值E,计算结果值V,比较此时E和计算之前E是否相等,若相等(ABA问题),更新为新值V,若不相等,重新读取E,重新计算。

1、ABA问题:
在CAS计算后,比较前后E的值相等时,例如A线程开始时E为0,B线程将E改为1,C线程将E又改为0,A线程计算完后比较E发现E和开始时一致,都为0,但是此时E是被改变过的。
解决方案: 增加版本号

2、原子性问题:
在和原E值比较相等之后,更新之前,可能出现(多核)别的CPU将原E值更新掉,CAS是如何保证这种情况原子性的?
汇编指令 lock -> 锁总线

自旋锁何时升级重量级锁?
当自旋锁旋转到一定的次数或者线程数大于CPU最大可接待的线程数,开始第二次锁升级,线程进入队列,由轻量级锁升级为重量级锁。


死锁

  • 死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的
    一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了
    死锁,这些永远在互相等待的进程(线程)称为死锁进程(线程)。

  • 多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻
    塞,因此程序不可能正常终止。

形成死锁的四个必要条件

  • 互斥条件:在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,就只能等
    待,直至占有资源的进程用毕释放。
  • 占有且等待条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进
    程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
  • 不可抢占条件:别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过
    来。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。(比如一个进程集合,A在
    等B,B在等C,C在等A)

如何避免线程死锁

  1. 避免一个线程同时获得多个锁
  2. 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
  3. 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制

AQS(AbstractQueuedSynchronizer)

传送门:
https://blog.csdn.net/weixin_40955398/article/details/122764766

线程池

传送门:
https://blog.csdn.net/weixin_40955398/article/details/122820050

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张矜持

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值