Java并发基础
一、关于并发的相关概念
1. 多线程、并发、并行、
并发:多个线程在同一时间段内同时执行。
并行:多个线程在同一时刻同时时执行。
通常一个处理器(或一个核)同一时刻只能处理一个线程,而线程在某些时候可能不需要cpu,在此时可以让cpu去执行其他地任务。为了充分地利用计算机资源,可以创建多个线程,在线程不需要cpu时,转而去执行其他的线程。
然而多线程会带来额外的开销:上下文切换、线程调度
2. 什么是上下文切换
当cpu从一个线程切换为另一个线程时,在切换前需要保存上一个线程的状态,切换后需要恢复下一个线程的状态。所以任务(线程)从保存到加载的过程就是一次上下文切换。
如何减少上下文切换
- 无锁并发编程:多线程竞争锁,会引起上下文切换(挂起)
- CAS算法:避免加锁
- 使用最少线程:
- 协程:单线程实现多任务的调度
3. 死锁
产生死锁的条件
- 资源互斥:一个资源最多只能由一个线程获得
- 请求保持:线程在请求其他资源时,不放弃已获得资源
- 不可剥夺:一个线程获得的资源无法被其他线程剥夺
- 环路等待: 资源的请求构成了请求环路
如何避免死锁
- 避免一个线程同时获取多个锁
- 使用定时锁
3. 多线程一定快吗
在一些情形下,多线程并不一定比单线程快:
- 任务量比较小,单线程在很短的时间内就能完成
- 资源限制,如网速、硬盘读写速度、数据库连接池
二、Java并发机制的底层原理
1. volatile
被volatile声明的变量,在修改时会发生两件事:
- 当前处理器缓存行的数据写回到系统内存
- 将其他CPU里缓存了该内存地址的数据置为无效
2. Synchronized
Java中所有的对象都可以作为锁(通过对象头标记),具体表现如下:
Synchronized作用于普通方法:锁是当前对象
Synchronized作用于静态方法:锁是当前类的Class对象
Synchronized作用于方法快:锁是括号中的对象
Java引入了偏向锁和轻量级锁,来减少获得锁和释放锁带来的性能损耗。锁一共有四章状态:无锁、偏向锁、轻量级锁、重量级锁。这几个状态,会随着竞争情况逐渐升级,锁可以升级但不能降级。
偏向锁
很多情况下,一个锁是总是由一个线程多次获得。获得偏向锁的线程再次获得该锁,可以直接获得,无需加锁和解锁。
轻量级锁
在获得锁时,自旋一定时间多次获得。
竞争的线程不会被阻塞,适用于同步块可以在很快。
重量级锁
3. 原子操作
Java实现原子操作可以通过锁和循环CAS的方式实现。
CAS带来的问题
- ABA问题
- 循环带来额外开销:
- 只能保证一个变量的原子性:
原文作者: NTJD
原文链接: http://yoursite.com/2020/08/13/Java并发基础/
版权声明: 转载请注明出处(必须保留作者署名及链接)