快速排序、归并排序、单例模式
快速排序
public static void quickSort(int[] arr, int left, int right) {
if (left >= right) {
return;
}
int i = left, j = right;
int pivot = arr[left];
while (i < j) {
//从右往左找第一个小于pivot的值
while (i < j && arr[j] >= pivot) {
j--;
}
//从左往右找第一个大于pivot的值
while (i < j && arr[i] < pivot) {
i++;
}
if (i < j) {
swap2(arr, i, j);
}
}
//一轮完成,把pivot换到中间位置
swap2(arr, i, left);
//递归处理左右数组
quickSort(arr, left, i - 1);
quickSort(arr, i + 1, right);
}
归并排序
public static void mergeSort(int[] nums, int l, int r){
//分而治之
//递归结束条件
if (l >= r){
return;
}
//划分
int m = (l + r) / 2;
mergeSort(nums, l, m);
mergeSort(nums, m + 1, r);
//合并子数组
//暂存左右数组
int[] tmp = new int[r - l + 1];
for (int k = l; k <= r; k++){
tmp[k - l] = nums[k];
}
//循环合并,i,j指针指向tmp数组的首元素
int i = 0;
int j = m - l + 1;
for (int k = l; k <= r; k++){
if (i == m - l + 1){ //左子数组已经结束
nums[k] = tmp[j++];
} else if (j == r - l + 1 || tmp[i] <= tmp[j]){
nums[k] = tmp[i++];
} else {
nums[k] = tmp[j++];
}
}
}
单例模式
public class Singleton {
// ============================================================
// 一、饿汉式单例模式
// ============================================================
/**
* 【饿汉式】
*
* 特点:类加载时就创建实例,不管是否使用
*
* 优点:
* 1. 实现简单
* 2. 线程安全(类加载时由JVM保证线程安全)
* 3. 没有锁的开销,性能高
*
* 缺点:
* 1. 类加载时就初始化,可能造成内存浪费(如果始终不使用)
* 2. 无法实现延迟加载
*
* 适用场景:
* - 单例对象占用内存小,初始化快
* - 确定一定会使用该单例
*/
static class EagerSingleton {
// 类加载时就创建实例
private static final EagerSingleton INSTANCE = new EagerSingleton();
// 私有构造函数,防止外部new
private EagerSingleton() {
}
// 提供全局访问点
public static EagerSingleton getInstance() {
return INSTANCE;
}
}
// ============================================================
// 二、懒汉式单例模式(线程不安全)
// ============================================================
/**
* 【懒汉式 - 线程不安全】
*
* 特点:第一次调用 getInstance() 时才创建实例
*
* 优点:
* 1. 实现了延迟加载,节省内存
*
* 缺点:
* 1. 线程不安全!多线程环境下可能创建多个实例
*
* 适用场景:
* - 单线程环境
* - 不推荐在生产环境使用
*/
static class LazySingletonUnsafe {
// 不立即创建实例
private static LazySingletonUnsafe instance;
private LazySingletonUnsafe() {
}
// 线程不安全的懒汉式
public static LazySingletonUnsafe getInstance() {
if (instance == null) {
instance = new LazySingletonUnsafe(); // 多线程可能同时执行到这里
}
return instance;
}
}
// ============================================================
// 三、懒汉式单例模式(线程安全 - 同步方法)
// ============================================================
/**
* 【懒汉式 - 线程安全(同步方法)】
*
* 特点:在 getInstance() 方法上加 synchronized 关键字
*
* 优点:
* 1. 线程安全
* 2. 实现延迟加载
*
* 缺点:
* 1. 每次获取实例都要加锁,性能差
* 2. 实际上只需要在第一次创建时加锁
*
* 适用场景:
* - 对性能要求不高的场景
*/
static class LazySingletonSafe {
private static LazySingletonSafe instance;
private LazySingletonSafe() {
}
// 整个方法加锁,性能较差
public static synchronized LazySingletonSafe getInstance() {
if (instance == null) {
instance = new LazySingletonSafe();
}
return instance;
}
}
// ============================================================
// 四、双重检查锁定(DCL)
// ============================================================
/**
* 【双重检查锁定 DCL (Double-Checked Locking)】
*
* 特点:双重检查 + volatile + 同步代码块
*
* 优点:
* 1. 线程安全
* 2. 延迟加载
* 3. 性能好(只在第一次创建时加锁)
*
* 缺点:
* 1. 实现稍复杂
* 2. 需要 volatile 防止指令重排序
*
* volatile 的作用:
* - 防止指令重排序
* - instance = new Singleton() 不是原子操作:
* 1. 分配内存空间
* 2. 初始化对象
* 3. 将引用指向内存地址
* - 没有 volatile,可能发生 2 和 3 重排序,导致其他线程拿到未初始化的对象
*
* 适用场景:
* - 需要延迟加载且对性能有要求的场景
* - 推荐!
*/
static class DCLSingleton {
// volatile 防止指令重排序
private static volatile DCLSingleton instance;
private DCLSingleton() {
}
public static DCLSingleton getInstance() {
// 第一次检查:避免不必要的锁
if (instance == null) {
synchronized (DCLSingleton.class) {
// 第二次检查:确保只创建一个实例
if (instance == null) {
instance = new DCLSingleton();
}
}
}
return instance;
}
}
// ============================================================
// 五、静态内部类(推荐)
// ============================================================
/**
* 【静态内部类】
*
* 特点:利用类加载机制实现延迟加载和线程安全
*
* 原理:
* - 外部类加载时不会加载内部类
* - 只有调用 getInstance() 时才会加载内部类
* - JVM 保证类加载的线程安全
*
* 优点:
* 1. 线程安全(JVM 保证)
* 2. 延迟加载(用到才加载内部类)
* 3. 不需要锁,性能最好
* 4. 实现简洁
*
* 缺点:
* 1. 无法传参初始化
*
* 适用场景:
* - 大多数场景都适用
* - 强烈推荐!
*/
static class StaticInnerSingleton {
// 私有构造
private StaticInnerSingleton() {
}
// 静态内部类,持有单例实例
private static class Holder {
private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton();
}
public static StaticInnerSingleton getInstance() {
return Holder.INSTANCE;
}
}
// ============================================================
// 六、枚举单例(最佳实践)
// ============================================================
/**
* 【枚举单例】
*
* 特点:利用枚举特性实现单例
*
* 优点:
* 1. 线程安全(枚举类加载时JVM保证)
* 2. 防止反序列化破坏单例
* 3. 防止反射攻击(枚举不能通过反射创建)
* 4. 实现最简洁
* 5. Effective Book 推荐!
*
* 缺点:
* 1. 无法延迟加载
* 2. 不能继承其他类(枚举已继承Enum)
*
* 适用场景:
* - 需要防止反序列化/反射攻击的场景
* - 不需要延迟加载的场景
* - 最佳实践!
*/
enum EnumSingleton {
INSTANCE;
// 可以添加方法
public void doSomething() {
System.out.println("EnumSingleton do something");
}
}
// ============================================================
// 测试代码
// ============================================================
public static void main(String[] args) {
// 测试饿汉式
EagerSingleton eager1 = EagerSingleton.getInstance();
EagerSingleton eager2 = EagerSingleton.getInstance();
System.out.println("饿汉式: " + (eager1 == eager2)); // true
// 测试DCL
DCLSingleton dcl1 = DCLSingleton.getInstance();
DCLSingleton dcl2 = DCLSingleton.getInstance();
System.out.println("DCL: " + (dcl1 == dcl2)); // true
// 测试静态内部类
StaticInnerSingleton inner1 = StaticInnerSingleton.getInstance();
StaticInnerSingleton inner2 = StaticInnerSingleton.getInstance();
System.out.println("静态内部类: " + (inner1 == inner2)); // true
// 测试枚举
EnumSingleton enum1 = EnumSingleton.INSTANCE;
EnumSingleton enum2 = EnumSingleton.INSTANCE;
System.out.println("枚举: " + (enum1 == enum2)); // true
enum1.doSomething();
}
}