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()方法添加一个请求时,线程池会做如下判断:
- 如果正在运行的线程数量小于corePoolSize时,那么马上创建线程运行这个任务
- 如果正在运行的线程数量大于等于corePoolSize,那么将这个任务放入队列
- 如果队列满了且正在运行的线程数量小于maximumPoolSize,那么将额外创建线程来处理这个任务
- 如果正在运行的线程数量大于等于maximumPoolSize,那么将启用拒绝策略RejectedExecutionHandler来处理
不建议使用Executors创建线程池
我们常用ThreadPoolTaskExecutor来自定义ThreadPoolExecutor工具,不建议使用Executors创建线程池的原因(参见阿里巴巴开发手册):
- newFixedThreadPool与newSingleThreadExecutor没有限制任务队列的大小,可能会因为堆积大量的请求导致OOM
- newCachedThreadPool与newScheduledThreadPool最大线程的大小限制为Integer.MAX_VALUE,可能创建大量的线程导致OOM
其它线程池参考文章:https://blog.csdn.net/qq_25806863/article/details/71126867