摘要:懒汉单例模式怎么变得线程安全?Master-Worker归并模式,工作窃取算法。Java线程相关源码使用了什么设计模式?
资料引用:《Java高并发核心编程·卷2》
目录
线程安全的单例模式
懒汉模式,即调用才创建的单例模式在高并发情况下,会有多个单例的情况。
解决方案-双重校验+volatile:
检查是否已经创建------>加锁创建过程------>创建前判断是否已经创建
第二次检查主要是防止其他线程已经通过第一次检查等待获取锁。
volatile关键字禁止实例创建过程中的指令重排。
java
/**
* 双重检查锁,解决多线程可能出现的多实例问题
*/
public class SingleTon2 {
private static volatile SingleTon2 singleton;
private SingleTon2() {
}
public static SingleTon2 getInstance() {
if (singleton == null) {
synchronized (SingleTon2.class) {
if (singleton == null) {
singleton = new SingleTon2();
}
}
}
return singleton;
}
//类中其他方法,尽量是static
public static void doSomething() {
System.out.println("doSomething");
}
}
Master-Worker模式
一种归并类型的模式。
任务的调度和执行分离,调度角色为Master,执行任务的角色为Worker,Master负责接收、分配任务和合并(Merge)结果,Woker执行任务。
Master-Worker 这种模式适合小规模任务分发。
大规模调度需另外设计如:事件驱动+MapReduce,去中心化、实时性、规模化处理更接近现代分布式架构。其设计目标是高效处理海量并发请求,保证准确性和一致性,而非简单依赖单一Master协调。
工作窃取算法
工作窃取算法的核心思想是:工作线程自己的活干完了之后,会去看看别人有没有没干完的活,如果有就拿过来帮忙干。工作窃取算法的主要逻辑:每个线程拥有一个双端队列(本地队列),用于存放需要执行的任务,当自己的队列没有任务时,可以从其他线程的任务队列中获得一个任务继续执行。
并发总结
对于并发、分布式来说,线程\节点之间的同步是有明显开销的,应该用尽可能少的同步做到相同的效果。
原则:
- 无锁优先:用CAS(如AtomicInteger)或无共享数据替代锁。
- 局部化:线程/节点尽量独立计算,减少交互。
- 异步化:用事件驱动或消息队列(如Kafka)解耦同步依赖。
- 最终一致性:分布式场景下,牺牲强一致性换取性能(如BASE模型)。
线程篇归纳
Thread
Java从线程的设计开始,除了设计有线程通用结构------线程ID、名称、状态、优先级,也为线程安全与线程状态流转做了设计。
且使用数字+枚举类转换的方式,减少了线程实例对象本身的运行开销。
对于线程状态的操纵,提供了不同的方法进行,对于阻塞状态,加重入锁。
对于线城池,Java将工作线程封装成Worker对象,并使用HashSet来存储工作线程,BlockingQueue来作为工作任务队列,且很好地使用了队列的阻塞方法来实现核心线程的不被清除。
JUC
JUC为了保证线程的原子性、可见性、有序性,大量使用CAS操作与volatile关键字。
能使用CAS的场景都使用了CAS,无锁优先,又针对CAS的问题,先后迭代有"热点分离"、"队列削峰"的设计来减少CAS自旋带来的性能损失。
对于CAS+volatile+版本号保证原子性、可见性、解决ABA问题,Java也设计有对应原子类如AtomicStampedReference等,使用的版本号为别的int类型与boolean类型。
异步
JUC异步模式有Master-Worker的归并模式,ForkJoin的异步使用"工作窃取算法"来提速分治后的任务处理速度。
代码质量
在线程相关的Java代码中,可以看到Java源码设计的非常严谨优雅,以线程池为例,基本设置为volatile保证可见性,对于没有设置volatile的属性,其仅在锁范围内使用。
又以CAS自旋为例,基本使用for(;;)的形式进行自旋。
体现了Java本身继承、封装、多态特性。以线程创建方式为例,体现有适配器与策略模式、模板方法等
高内聚、低耦合,且兼顾灵活与性能。
模式总结
Thread:
适配器(适配Runnable)
模板方法(run()定制)
JUC:
单例、工厂(线程池创建)
策略(拒绝策略)
装饰器(FutureTask)
观察者(CompletableFuture)
代理(ExecutorService)
状态(线程池状态)
建造者(复杂配置)
工作窃取(ForkJoinPool)
读写锁(ReentrantReadWriteLock)