高并发(high concurrency)
缓存一致性协议(MESI)
Modified | Exclusive | Shared | Invalid |
---|---|---|---|
修改的 | 独享的 | 共享的 | 无效的 |
注:乱序执行优化
Java内存模型(JMM)
1.读取(Read)载入(Load),存储(Store)写入(Write)必须成对出现
2.不允许丢弃赋值(Assign),必须存储(Store),写入(Write)
3.没有赋值(Assign),不允许存储(Store),写入(Write)
4.没有读取(Read)载入(Load),不允许使用(Use)
5.变量不能被多个线程锁定(Lock),锁定(Lock)解锁(Unlock)次数相等
6.锁定(Lock)之后会清空线程值,使用需重新读取(Read)载入(Load)
7.没有进行锁定(Lock),不允许进行解锁(Unlock)
8.解锁(Unlock)时必须存储(Store)写入(Write)
1.线程安全性:多线程无视调度方式,不需额外同步协同,能表现出正确行为
- 原子性:互斥访问,同一时刻只有一个线程进行操作
- AtomicXXX : Unsafe类CAS实现
存在ABA问题(AtomicStampedReference解决) - Synchronized : 依赖JVM锁
局部锁(当前对象):修饰代码块,修饰方法
全局锁(所有对象):代码块中锁对象为XXX.class,修饰静态方法 - Lock : 依赖特殊的CPU指令
ReetrantLock : 可重入锁
- AtomicXXX : Unsafe类CAS实现
- 可见性:一个线程对主内存的修改可以被其他线程观察到
- 原因:交叉运行,乱序优化,修改未及时同步
- Synchronized : 锁定后清空,解锁时写入
- Volatile : 加入XY屏障,禁止重排序(禁止屏障前X与屏障后Y重排)
写操作在前加storestore,在后加storeload屏障
读操作在后加loadload和loadstore屏障
- 有序性:观察线程指令执行顺序,由于指令重排造成结果无序
Java保证指令重排不影响单线程,happens-before原则
2.安全发布对象
- 发布对象:是一个对象能够被当前范围之外的代码使用
- 对象逸出:当一个对象还没有完全构造完成时就被其他线程所见
- 安全发布
- 静态初始化函数中初始化一个对象
- 将对象引用保存到volatile类型域或AtomicReference对象中
- 将对象引用保存到正确构造对象的final域中
- 将对象引用保存到由锁保护的域中
3.线程安全策略
- 不可变对象(共享只读):
创建以后不可修改,final修饰所有域,无this逸出,
不可变的集合:Collections.unmodifiableXXX , ImmutableXXX… - 线程封闭(线程限制):局部变量,ThreadLocal
- 同步容器(线程安全对象):
Vector , Stack,HashTable , Collections.synchronizedXXX… - 并发JUC容器(被守护对象):
CopyOnWriteArrayList , CopyOnWriteArraySet , ConcurrentSkipListSet , ConcurrentHashMap , ConcurrentSkipListMap…
4.JUC之AQS:AbstractQueuedSynchronizer
- CountDownLatch , 线程等待
- Semaphore , 信号量
- CyclicBarrier , 线程并进
- ReentrantLock:
与synchronized的区别:可重入,依靠AQS实现,性能好,功能多
独有功能:可选择公平性,可Condition分组唤醒,能中断等待锁
其他:StampedLock,ReentrantReadWriteLock - 扩展:
FutureTask : 实现Runnable和Future接口,有返回结果的异步任务
ForkJoin : 密集计算任务拆分进行,任务密取
BlockingQueue : 阻塞队列,生产者和消费者模式
5.线程池
- ThreadPoolExecutor
Executors.newCachedThreadPool
Executors.newFixedThreadPool
Executors.newScheduledThreadPool
Executors.newSingleThreadExecutor - 参考配置
计算密集型:CPU数量+1
IO密集型:CPU数量*2
死锁
条件:互斥,请求和保持,不剥夺,环路等待
最佳实践:
- 使用本地变量
- 使用不可变类
- 最小化锁的作用域s=1/(1-a+a/n)
- 使用线程池,而不是Thread
- 使用同步工具,而不是wait,notify
- 使用BlockingQueue实现生产消费者模式
- 使用并发集合,而不是同步集合
- 使用Semaphore创建有界访问
- 使用同步代码块,而非同步方法
- 使用不可变的静态变量
优化思路:
- 扩容
服务器(垂直扩展/水平扩展)
数据库(读扩展:Memcache,redis,CDN/写扩展:Cassandra,Hbase) - 缓存(本地缓存:编程实现,GuavaCache/分布式缓存:Memcache,Redis)
因素:命中率:业务需求,粒度策略,容量基础/最大元素/清空策略
问题:一致,并发,穿透,雪崩 - 消息队列
特点:只做分发,先进先出,容灾,性能
优点:业务解耦,最终一致,广播,流控
Kafka,RabbitMQ,ActiceMQ,RocketMQ… - 应用拆分
原则:业务优先,循序渐进,兼顾技术,可靠测试
思考:通信机制选择,数据库设计,避免跨应用 - 应用限流
算法:计数器法,滑动窗口,漏桶算法,令牌桶算法 - 熔断降级
共性:目的,表现,粒度,自治
区别:触发原因,管理目标层次,实现方式 - 切库分库分表
瓶颈:数据量,吞吐量
切库:读写分离
分表:横向,纵向 - 高可用
任务调度系统分布式:elastic-job+zookeeper
主备切换:apache-curator+zookeeper分布式锁实现
监控报警