多线程、并发重点总结

JMM(Java内存模型)

线程同步
  • 线程解锁前,必须把共享变量的值刷新回主内存
  • 线程加锁前,必须将自己的内存更新为主内存的值
  • 加锁解锁为同一把锁
指令重排
  • 为了提高性能编译器和处理器常常会对指令做重排序
  • 指令重排必须考虑指令之间的数据依赖性

volatile,Java虚拟机提供的轻量级同步机制

  • 保证内存可见性不保证原子性
  • 禁止指令重排

CAS相关

  • 比较与交换
  • Unsafe是CAS核心类,如:AtomicInteger底层就是通过UNsafe实现,里面所有的方法都通过native修饰,用native修饰的方法可以直接调用操作系统底层资源执行相应的任务。
  • CAS是一条CPU并发原语,原语执行必须连续,不允许中断。
  • 缺点:比较一直不成功循环开销大,只能保证一个变量原子操作,ABA问题

CAS带来ABA问题的解决

  • 每个操作增加版本号,代表类atomicStampedReference。类似于数据库并发控制的MVCC同样是为每个事物增加版本号。

公平锁非公平锁

  • 公平锁按照申请顺序,非公平锁上来就直接尝试占用锁,如果尝试失败,就采用类似公平锁的方式。
  • 非公平锁缺点会造成优先级反转或者饥饿现象。
  • 非公平锁优点,吞吐量比公平锁大
  • ReentrantLock与Synchronized均默认非公平锁。

可重入锁

  • 线程可以进入任何一个它已经拥有的锁所同步的代码块
  • ReentrantLock与Synchronized均为可重入锁

自旋锁

  • 获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,可以减少线程上下文切换的消耗,缺点是循环会消耗CPU

解决集合线程安全类

  • Vector、Collections.synchronizedList(new ArrayList())
  • CopyOnWriteArrayList、CopyOnWriteArraySet、ConcurrentHashMap
  • CopyOnWriteArrayList运用了读写分离的思想

独占锁、共享锁、互斥锁

  • 独占锁:一次只能被一个线程持有,ReentrantLock和Synchronized都是独占锁
  • 共享锁:改锁可以被多个线程锁持有
  • ReentrantReadWriteLock其读锁是共享锁,写锁是独占锁,读写与写写是互斥的

CountDownLatch、CyclicBarrier、Semaphore作用以及区别

  • CountDownLatch、火箭发射倒计时,做的减法,全部线程减到0之后await解除,才可以执行下一段程序
  • CyclicBarrier、集齐龙珠召唤神龙,做的加法,先到先等,全部到齐,全部await解除,才可以执行下个主程序。
  • Semaphore、加减法并用、经典抢车位、多个共享资源互斥,并发线程数的控制。用完的资源及时释放,资源将再次被其它线程争抢利用。

阻塞队列

一种特定的list,继承关系图如下:
在这里插入图片描述

  • ArrayBlockingQueue,数组组成的有界阻塞队列
  • LinkedBlockingQueue,链表组成的有界阻塞队列,但是默认值为Integer.MAX_VALUE
  • SynchronousQueue,不存储元素也可以认为只有单个元素的队列

synchronized与lock的区别

  • synchronized属于jvm层面,通过monitor对象来完成,lock是具体类,属于aip层面;
  • synchronized不需要手动释放锁,lock需要手动释放锁
  • synchronized不可中断,除非抛出异常或者运行完成,ReentrantLock可以中断,设置超时时间或者interrupt()方法中断。
  • synchronized非公平锁,ReentrantLock两者都可以
  • ReentrantLock可以绑定多个条件Condition,精确唤醒,分组环境;synchronized只能随机唤醒或者全部唤醒

通过实现Callable接口实现线程

  • 相对于实现Runnable接口,方法可以有返回值,可以抛出异常
  • 需要结合FutureTask使用,用于接收运算结果
  • FutureTask继承runnable接口同时以callable作为构造参数,所以具备了线程功能以及获取运算结果的功能

ThreadPoolExecutor七大参数以及拒绝策略

拒绝策略参考文章:https://blog.csdn.net/qq_25806863/article/details/71172823
ThreadPoolExecutor相关文章:https://blog.csdn.net/qq_25806863/article/details/71126867
我们常用ThreadPoolTaskExecutor来作为ThreadPoolExecutor工具

七大参数简介:
  • corePoolSize:核心线程数
  • maximumPoolSize:线程池所能容纳的最大线程数
  • keepAliveTime:非核心线程的闲置超时时间,超过这个时间就会被回收
  • unit:指定keepAliveTime的单位
  • workQueue:线程池中的任务队列.
  • threadFactory:线程工厂,提供创建新线程的功能
  • RejectedExecutionHandler:当线程池中的资源已经全部使用,添加新线程被拒绝时,会调用RejectedExecutionHandler的rejectedExecution方法。拒绝策略参考好文:
    ThreadPoolExecutor的拒绝策略
线程池处理流程,当调用execute()方法添加一个请求时,线程池会做如下判断:
  1. 如果正在运行的线程数量小于corePoolSize时,那么马上创建线程运行这个任务
  2. 如果正在运行的线程数量大于等于corePoolSize,那么将这个任务放入队列
  3. 如果队列满了且正在运行的线程数量小于maximumPoolSize,那么将额外创建线程来处理这个任务
  4. 如果正在运行的线程数量大于等于maximumPoolSize,那么将启用拒绝策略RejectedExecutionHandler来处理
不建议使用Executors创建线程池

我们常用ThreadPoolTaskExecutor来自定义ThreadPoolExecutor工具,不建议使用Executors创建线程池的原因(参见阿里巴巴开发手册):

  1. newFixedThreadPool与newSingleThreadExecutor没有限制任务队列的大小,可能会因为堆积大量的请求导致OOM
  2. newCachedThreadPool与newScheduledThreadPool最大线程的大小限制为Integer.MAX_VALUE,可能创建大量的线程导致OOM

其它线程池参考文章:https://blog.csdn.net/qq_25806863/article/details/71126867

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值