并发编程小结

Java并发编程小结

在这里插入图片描述

1.CPU多级缓存–缓存一致性

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

2.线程安全了解

2.1环境初始化----项目搭建
Spring Boot项目和GiT使用
2.2案例准备工作
2.3并发模拟–工具
Postman:http请求模拟工具
Apache Bench:Apache附带的工具,测试网站性能
JMeter:Apache组织开发的压力测试工具
2.4并发模拟–代码
CountDownLatch:阻塞线程,并保证在某种限定下线程仍可执行
Semaphore:阻塞进程,并控制同一时间的并发量

3.线程安全性

3.1原子性
Atomic包
*AtomicLong低并发占优势
* LongAdder{低并发(Base) 高并发(分散)}
CAS算法 (compare and swap)
synchronized (依赖JVM)
Lock (依赖特殊的CPU指令)
对比:
1. synchronized:不可中断锁,适合竞争不激烈,可读性好
2.Lock:可中断锁,多样化同步,竞争激烈时能维持常态
3.Atomic:竞争激烈时维持常态,比Lock性能好,只能同步一个值
3.2可见性—Synchronized
1.导致共享变量在线程间不可见的原因
◎线程交叉执行
◎重排序结合线程交叉执行
◎共享变量更新后的值没有在工作内存与主内存之间及时更新
2.解锁前刷新主内存 ,加锁前清空主内存
3.可见性
volatile 适合做状态标识
加入内存屏障和禁止重排序 (在CPU指令级别操作) 3.3有序性 happens~before原则
1.程序次序规则
2.锁定规则
3.volatile变量规则
4.传递规则
5.线程启动规则(start())
6.线程中断规则(interrupt())
7.线程终结规则
8.对象终结规则

4.安全对象

4.1发布对象和对象溢出
发布对象:使一个对象能够被当前范围之外的代码使用
对象溢出:一种错误的发布。当一个对象还没有构造完成时,就使他被其他线程所见
4.2安全发布对象(4种方法)
①在静态初始化函数中初始化一个对象使用
②将对象的引用保存在volatile类型域或者AtomicReference对象中
③将对象的引用保存到某个正确构造对象的final类型域中
④将对象的引用保存到一个由锁保存的域中
注意
① 不安全~懒汉模式—单例实例在第一次使用时进行创建 (添加synchronized后safe了,但是会带来性能开销)
② 安全~饿汉模式—单例实例在装载时进行创建
③ 双重同步锁单例模式—有指令重排的问题(添加volatile后safe了,禁止指令重排)

5.不可变对象

5.1不可变对象满足的条件(参考string类)
①对象创建后,其状态不可被修改
②对象所有域都是final类型
③对象是正确创建的(在对象创建期间,this引用没有溢出)
5.2 Java其他方法定义不可变对象 ①Collections.unmodifiable××× ②Guava:Immutable×××
(×××指collection:list set map)

6.线程封闭

①.封闭方法:Ad-hoc线程封闭:程序控制实现(不建议使用) ②.堆栈封闭:局部变量,无并发问题
③.ThreadLocal线程封闭:比较好的封闭方法

7.线程不安全类与安全类的总结对比

①StringBuilder–unsafe StringBuffer–safe ②SimpleDateFormat–unsafe(每次声明一个对象来使用) JodaTime.DateTimeFormat–safe(更推荐)
③Collections集合–unsafe
例如 ArrayList HashSet HashMap

8.线程安全–同步容器(主要是使用synchronized,并不是完全安全,而且会影响性能)

ArrayList----> Vector,Stack
HashMap---->HashTable(key,value不能为空)
Collection.synchronizedxxx(List,Set,Map)

9.线程安全–并发容器(J.U.C)

①ArrayList~>CopyOnWriteArrayList
思想:
☆读写分离
☆最终一致性
☆使用时另外开辟空间
注意: 读操作实在原数据上读,不用加锁
缺点:
☆要考虑内存
☆不能用于实时读 ②HashSet~>CopyOnWriteArraySet
注意: 可变容器,不支持remove操作,适合少写多读
③TreeSet~>ConcurrentSkipListSet
注意:
☆JDK6增加的
☆支持自然排序
☆基于Map集合
☆单个线程安全,多个线程则不能保证其原子性 ④HashMap~>ConcurrentHashMap
高并发凸显其优势,读优先 ⑤TreeMap~>ConcurrentSkipListMap
内部通过SkipList实现,key有序,支持更高的并发

10.安全共享对象策略–总结

①线程限制:一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改
②共享只读:一个共享只读的对象,在没有额外同步的情况下,可以被多个线程并发访问,但任何线程都不能修改它
③线程安全对象:一个线程安全的对象或容器,在内部通过同步机制来保证线程安全,所以其他线程无需额外同步就可以通过公共接口随意访问它
④被守护对象:被守护对象只能通过过去特定的锁来访问

11. AQS

11.1 AQS的简介
①使用Node实现FIFO队列,可用于构建领域其他同步装置的基础框架
②利用了一个int类型表示状态
③使用方法是继承
④子类通过继承并通过实现它的方法管理其状态{acquire , release}
⑤可以同时实现排它锁和共享模式(独占,共享)
11.2 AQS重要的同步组件
11.2.1 CountDownLatch
☆支持给定时间的等待,使用时要给定计数器
☆核心方法:{countDown() , await()}
☆使用场景:例如并行计算
11.2.2 Semaphore(信号量)
☆通过提供同步机制来控制某个资源可被同时访问的线程个数
☆核心方法:{acquire() , release()}
☆使用场景:仅能提供有限访问的资源
11.2.3 CyclicBarrier
☆可循环使用(reset()充值计数器)
☆允许一组线程相互等待
☆通过计数器实现的
☆核心方法:await()
☆使用场景:可使用于多线程计算数据,最后合并计算结果
11.2.4 ReentrantLock 与 锁
①ReentrantLock 与 Semaphore的区别
在这里插入图片描述

②ReentrantLock独有的功能:
☆可指定是公平锁还是非公平锁
☆提供了一个Condition类,可以分组唤醒需要唤醒的线程
☆提供能够中断等待锁的线程的机制Lock.lockInterruptibly()
11.2.5ReentrantLockRead/WriteLock
☆在没有任何读、写时,才可以写入
☆问题:若使用锁,读多写少,则会出现写饥饿现象
11.3 FutureTask(是J.U.C的中的,但不是AQS的组件)(JDK1.5)
●适用于启动线程去做一些事情,并且关注它的结果
①Callable 与 Runnable接口对比
C泛型接口,对线程执行后有返回值,并且能抛出异常
②Future接口 可以监视目标线程调用call的情况
③FutureTask类 继承Runnable和Future
11.4 Fork/Join框架(采用工作窃取算法)
①同步机制:只能使用Fork和Join
②不能实现I/O操作
③不能检查抛出异常,必须手动用代码实现
11.5 BlockingQueue阻塞队列
☆线程安全
☆主要用于生产者-消费者场景
☆可以弥补开发人员易忽略的点,从而让开发人员关注更高级的功能
●ArrayBlockingQueue
有界阻塞队列;底层用Array实现;先进先出 ●DelayQueue
阻塞内部元素;底层用的是排序和锁 ●LinkedBlockingQueue
底层用Link实现;先进先出
●PriorityBlockingQueue
无边界;有排序规则;允许插入null对象;使用时必须实现Compareable接口
●SynchronousQueue
内部仅容纳一个元素;无界非缓存队列;又叫同步队列

12.线程池

12.1 new Thread的弊端
①每次new Thread需要新建对象,性能差
②线程缺乏统一管理
③缺少更多的功能,如:更多执行,定期执行,线程中断
12.2 线程池的好处
①重用存在的线程,减少对象创建、消亡的开销,性能佳
②可有效控制最大并发线程数,提高系统资源利用率,可以同时避免过多资源的竞争,避免阻塞
③提供定时执行,定期执行,单线程,并发数控制等功能
12.3 线程池相关的类
ThreadPoolExecutor
属性 :
☆corePoolSize
☆maximumPoolSize
☆workQueue(直接切换,无界,有界)
☆keepAliveTime
☆unit:keepAliveTime的单位
☆threadFactory
☆rejectHandler:当拒绝处理任务时的策略
方法:
☆execute():提交任务,交给线程池执行
☆submit():提交任务,能够返回执行的结果
☆shutdown():关闭线程池,等待任务都执行完
☆shutdownNow():关闭线程池,不等待
☆getTaskCount():线程池已执行和未执行的任务总数量
☆getPoolSize():当前的线程数量
☆getCompletedTaskCount():已完成的线程任务数量
☆getActiveCount():正在执行的线程数量
12.4线程池-Executor框架接口
①Executors.newCachedThreadPool
长度可变
②Executors.newFixedThreadPool
控制最大并发数
③Executors.newScheduledThreadPool
定时,周期性,定长
④Executors.newSingleThreadPool
按指定顺序执行
12.5 线程池-合理配置
●CPU密集型任务,就需要尽量压榨CPU,参考值可设为nCPU+1
●I/O密集型任务,参考值可设置为2*nCPU

13.多线程并发最佳实践(总结)

①使用不可变类
②使用本地变量
③最小化锁的作用域范围(阿姆安达尔定理)
④使用线程池的Executor,而不是直接new Thread执行
⑤宁可使用同步,也不要使用线程的wait和notify
⑥使用BlockingQueue实现生产-消费模式
⑦使用并发集合而不是加了锁的同步集合
⑧使用Semaphore创建有界的访问
⑨宁可使用同步代码块,也不使用同步的方法
⑩避免使用静态变量

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值