// 1. 类 final
public final class ImmutableUser {
// 2. 属性 private final
private final String name;
private final int age;
// 3. 构造器一次性赋值
public ImmutableUser(String name, int age) {
this.name = name;
this.age = age;
}
// 4. 只有 getter,没有 setter
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
思想
对象创建后不可修改,只读对象天然线程安全。
实现方式
类和属性用final修饰。
去除setter方法,仅保留getter。
适用场景
缓存数据、配置信息、操作系统只读数据。
注意事项
可变对象即使属性为final也无法保证线程安全。
应避免暴露内部可变状态。
2.2.2 写实复制(Copy-on-Write)
java复制代码
import java.util.Arrays;
import java.util.concurrent.locks.ReentrantLock;
// 手写极简版 CopyOnWriteArrayList
public class SimpleCopyOnWriteList<E> {
// 真正存数据的数组,volatile 保证可见性
private volatile Object[] array;
// 写操作加锁,防止多线程同时复制
private final ReentrantLock lock = new ReentrantLock();
// 构造:空数组
public SimpleCopyOnWriteList() {
array = new Object[0];
}
// ==================== 读方法:不加锁,直接读 ====================
public E get(int index) {
return (E) array[index];
}
public int size() {
return array.length;
}
// ==================== 写方法:加锁 + 复制新数组 ====================
public boolean add(E e) {
lock.lock();
try {
// 1. 获取旧数组
Object[] oldArr = array;
// 2. 复制一个新数组,长度+1
Object[] newArr = Arrays.copyOf(oldArr, oldArr.length + 1);
// 3. 在新数组上添加元素
newArr[oldArr.length] = e;
// 4. 把引用指向新数组(volatile 保证其他线程立刻看到)
array = newArr;
return true;
} finally {
lock.unlock();
}
}
}
原理
修改对象时不直接修改原对象,而是复制一份再修改。
典型应用
CopyOnWriteArrayList在写操作时复制数组。
操作系统fork进程时也采用该机制。
优点
适用于读多写少场景。
缺点
内存占用高。
2.2.3 线程本地存储(ThreadLocal)
java复制代码
public class ThreadLocalTest {
// 定义 ThreadLocal
private static final ThreadLocal<Integer> TL = ThreadLocal.withInitial(() -> 0);
public static void main(String[] args) {
// 线程1 +10
new Thread(() -> {
TL.set(TL.get() + 10);
System.out.println("线程1:" + TL.get()); // 10
}).start();
// 线程2 +20
new Thread(() -> {
TL.set(TL.get() + 20);
System.out.println("线程2:" + TL.get()); // 20
}).start();
}
}