0903(046天 线程集合总结01)
0903(046天 线程集合总结01)
每日一狗(旺名)
大标题
文章目录
- 0903(046天 线程集合总结01)
- 大标题
- 1. 一级标题
- 1.1 二级标题
- 1.2 迭代器模式
- 1.3 二级标题
- 1.4 二级标题
- 2. 迭代器
- 2.1 二级标题
- 2.2 二级标题
- 2.3 二级标题
- 2.4 二级标题
- 3. 并发编程和集合框架 总结 问:
- 3.1 并发编程
- 并发编程的三种性质
- 并发编程的三个问题
- volatile
- 预防死锁
- 3.2 锁的分类
- 常见的锁
- 操作系统会影响点东西
- 公平锁与非公平锁
- 3.3 并发集合
- 两种解决并发集合安全方法
- ConcurrentHashMap
- 3.4 编程模型CAS
- 扩展小芝士
- 模板备份开始
- 4. 一级标题
- 4.1 二级标题
- 4.2 二级标题
- 4.3 二级标题
- 4.4 二级标题
- 模板备份结束
1. 一级标题
1.1 二级标题
1.2 迭代器模式
1.3 二级标题
1.4 二级标题
2. 迭代器
2.1 二级标题
2.2 二级标题
2.3 二级标题
2.4 二级标题
3. 并发编程和集合框架 总结 问:
3.1 并发编程
并发编程的三种性质
- 可见性
- 原子性
- 有序性
并发编程的三个问题
- 线程安全安全
- 活跃性:死锁、活锁、饥饿
- 性能
- 无锁
- 降低锁颗粒度
volatile
Java中会第一时间将自己的数据同步到内存中去,而且还会防止Java编译器的重排优化,保证有序性。
可见性
有序性
无法保证原子性
预防死锁
死锁的必要条件有四个,只需要破坏其中一项就可以解决死锁
- 互斥:synchronized就互斥呀,没法改,
- 占有且等待:同时申请多把锁
- 不可抢占:synchronized没辙,Lock可以
- 循环等待:为资源设定id,你得有这个才能申请那个,按照顺序申请
同步方法锁使用对象头实现,被synchronized修饰的方法会在方法区有一个标识ACC_SYCHRONIZED来进行标识;同步代码块使用了两个机器码来进行进入monitorenter和退出:monitorexit(有俩退出,一个异常一个正常)。
3.2 锁的分类
常见的锁
-
阻塞:需要进行状态转换
-
自旋:轻量级锁,忙等锁
-
可重入锁:自己拿着锁,自己再去申请锁直接拿到。(一定程度避免死锁)
-
读写锁:主要提高数据读写的并发性。
- 读读不互斥
- 读被申请走了,写锁无法被其他线程申请;写锁被申请走了,读锁无法被其他线程申请。
- 有读拿写锁不行;有写拿读锁可以
-
独享锁、共享锁 通过AQS来进行实现
- 独享锁。就是排它锁
- 共享锁。读锁就是共享锁
-
乐观、悲观:是面对线程安全问题的一种态度
-
乐观:轻易不出现安全问题,出现了我自己补偿(CAS),适合大量的读操作
Java搞了很多的原子类来应对CAS操作
-
悲观:肯定有问题,先上互斥锁了再说,适合大量的写操作
-
-
无锁、偏向锁、轻量级锁、重量级锁(会升级,但是不会退化)
-
自旋锁:忙等状态。
-
自适应自旋锁:忙等次数过多会被阻塞。由前一个线程阻塞的次数和锁的拥有者的状态进行动态
锁消除:1.6+引入的逃逸分析
对一些根本就是同步的程序将锁给
操作系统会影响点东西
- 线程加锁和释放锁,由于操作系统的原因,这中间需要在用户态和核心态之间来回切换,消耗巨大
- 线程优先级,尽可能拉大点,不同系统拥有的优先级等级不一定可以一一对应。
公平锁与非公平锁
公平:会比非公平锁多判定一个阻塞队列中是否有被阻塞的队列,队列有线程阻塞这就会把自己加到队列中
非公平锁:看锁没人用,没人就加锁,有才会去阻塞。
3.3 并发集合
两种解决并发集合安全方法
加锁:给这几个桶加一把锁,另几个桶加一把锁,不同桶之间可以并发,桶内互斥。可以降低锁的颗粒度。
List<Integet> list =
Collections.synchronizedList(new ArrayList());
拷贝后写入:搞一份备份,改的时候改这个备份,改完了改一个引用就行。
List<Integer> list =
new CopyOnWriteArrayList<Integer>();
ConcurrentHashMap
一开始的锁数组无法扩容,然后这个锁数组中存储的那个引用数组,这个数组才是可以扩容的。
1.7+:数组+Segment分段锁+单项链表。这种颗粒度太大了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H6Zid1jP-1662202120185)(assets/image-20220903163846007.png)]
1.8+:数组+链表+红黑树,不分段了,直接给桶加锁,频繁加锁解锁影响性能,这里使用CAS保证数据的安全性。 Node:保存key,value及key的hash值的数据结构。其中value和next都用volatile修饰,保证并发的可见性。
JDK8中放弃了分段锁。
键值都不允许为null
3.4 编程模型CAS
为了以不加锁的方式实现加锁的效果。
扩展小芝士
- 多线程常用于频繁进行用户交互的时候;计算密集型不适合用多线程
- CAS的判定写会的原子性从机器指令上进行保证