
package cn.meowrain;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadSafetyAnalysis {
// --- 成员变量和静态变量是否线程安全? ---
// 1. 成员变量 (非静态)
// 1.1 如果它们没有共享, 则线程安全
static class MemberVarNotShared {
private int count = 0; // 成员变量
public void incrementAndPrint() {
count++;
System.out.println(Thread.currentThread().getName() + ": count = " + count);
}
public static void demo() throws InterruptedException {
System.out.println("--- 1.1 成员变量 - 没有共享 (每个线程一个新对象) ---");
Thread t1 = new Thread(() -> new MemberVarNotShared().incrementAndPrint(), "T1_MemberNotShared");
Thread t2 = new Thread(() -> new MemberVarNotShared().incrementAndPrint(), "T2_MemberNotShared");
t1.start();
t2.start();
t1.join();
t2.join();
// 输出会是 T1: count = 1, T2: count = 1 (顺序不定)
// 因为每个线程操作的是不同对象的 count 成员变量
}
}
// 1.2 如果它们被共享了
// 1.2.1 如果只有读操作, 则线程安全
static class SharedMemberVarReadOnly {
private final String message = "Hello, World!"; // final 确保了初始化后不可变
public void printMessage() {
System.out.println(Thread.currentThread().getName() + ": message = " + message);
}
public static void demo() throws InterruptedException {
System.out.println("\n--- 1.2.1 共享成员变量 - 只有读操作 ---");
SharedMemberVarReadOnly sharedReader = new SharedMemberVarReadOnly();
Thread t1 = new Thread(() -> sharedReader.printMessage(), "T1_SharedRead");
Thread t2 = new Thread(() -> sharedReader.printMessage(), "T2_SharedRead");
t1.start();
t2.start();
t1.join();
t2.join();
// 线程安全,因为 message 是 final 且只被读取
}
}
// 1.2.2 如果有读写操作, 则这段代码是临界区, 需要考虑线程安全
// 1.2.2.a) 非线程安全示例
static class SharedMemberVarReadWriteUnsafe {
private int count = 0; // 共享成员变量
public void increment() {
count++; // 读-改-写 操作,非原子
}
public int getCount() {
return count;
}
public static void demo() throws InterruptedException {
System.out.println("\n--- 1.2.2.a 共享成员变量 - 读写操作 (不安全) ---");
SharedMemberVarReadWriteUnsafe unsafeCounter = new SharedMemberVarReadWriteUnsafe();
int numThreads = 1000;
CountDownLatch latch = new CountDownLatch(numThreads);
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < numThreads; i++) {
executor.submit(() -> {
unsafeCounter.increment();
latch.countDown();
});
}
latch.await();
executor.shutdown();
System.out.println("Unsafe counter final count: " + unsafeCounter.getCount() + " (Expected " + numThreads + ", but likely less)");
// 结果通常会小于 1000,因为 count++ 不是原子操作
}
}
// 1.2.2.b) 线程安全示例 (使用 synchronized)
static class SharedMemberVarReadWriteSafe {
private int count = 0; // 共享成员变量
public synchronized void increment() { // synchronized 保护临界区
count++;
}
public int getCount() {
return count;
}
public static void demo() throws InterruptedException {
System.out.println("\n--- 1.2.2.b 共享成员变量 - 读写操作 (安全 - synchronized) ---");
SharedMemberVarReadWriteSafe safeCounter = new SharedMemberVarReadWriteSafe();
int numThreads = 1000;
CountDownLatch latch = new CountDownLatch(numThreads);
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < numThreads; i++) {
executor.submit(() -> {
safeCounter.increment();
latch.countDown();
});
}
latch.await();
executor.shutdown();
System.out.println("Safe counter (synchronized) final count: " + safeCounter.getCount() + " (Expected " + numThreads + ")");
// 结果会是 1000
}
}
// 2. 静态变量 (总是被共享)
// 2.1 如果只有读操作, 则线程安全 (同成员变量)
static class SharedStaticVarReadOnly {
private static final String STATIC_MESSAGE = "Static Hello!";
public void printStaticMessage() {
System.out.println(Thread.currentThread().getName() + ": static message = " + STATIC_MESSAGE);
}
public static void demo() throws InterruptedException {
System.out.println("\n--- 2.1 共享静态变量 - 只有读操作 ---");
SharedStaticVarReadOnly readerInstance1 = new SharedStaticVarReadOnly();
SharedStaticVarReadOnly readerInstance2 = new SharedStaticVarReadOnly(); // 即使不同实例,静态变量也是同一个
Thread t1 = new Thread(() -> readerInstance1.printStaticMessage(), "T1_StaticRead");
Thread t2 = new Thread(() -> readerInstance2.printStaticMessage(), "T2_StaticRead");
t1.start();
t2.start();
t1.join();
t2.join();
}
}
// 2.2 如果有读写操作, 则需要考虑线程安全
// 2.2.a) 非线程安全示例
static class SharedStaticVarReadWriteUnsafe {
private static int staticCount = 0;
public void incrementStatic() {
staticCount++;
}
public static int getStaticCount() {
return staticCount;
}
public static void demo() throws InterruptedException {
System.out.println("\n--- 2.2.a 共享静态变量 - 读写操作 (不安全) ---");
// 重置一下计数器,因为它是静态的,会被之前的测试影响(如果在同一个JVM实例中运行多次)
staticCount = 0;
SharedStaticVarReadWriteUnsafe unsafeStaticCounter1 = new SharedStaticVarReadWriteUnsafe();
SharedStaticVarReadWriteUnsafe unsafeStaticCounter2 = new SharedStaticVarReadWriteUnsafe();
int numThreads = 1000;
CountDownLatch latch = new CountDownLatch(numThreads);
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < numThreads; i++) {
executor.submit(() -> {
// 随机使用不同实例的方法,但它们操作的是同一个静态变量
if (Math.random() > 0.5) {
unsafeStaticCounter1.incrementStatic();
} else {
unsafeStaticCounter2.incrementStatic();
}
latch.countDown();
});
}
latch.await();
executor.shutdown();
System.out.println("Unsafe static counter final count: " + getStaticCount() + " (Expected " + numThreads + ", but likely less)");
}
}
// 2.2.b) 线程安全示例 (使用 AtomicInteger)
static class SharedStaticVarReadWriteSafe {
private static AtomicInteger atomicStaticCount = new AtomicInteger(0);
public void incrementStaticAtomic() {
atomicStaticCount.incrementAndGet();
}
public static int getAtomicStaticCount() {
return atomicStaticCount.get();
}
public static void demo() throws InterruptedException {
System.out.println("\n--- 2.2.b 共享静态变量 - 读写操作 (安全 - AtomicInteger) ---");
atomicStaticCount.set(0); // 重置
SharedStaticVarReadWriteSafe safeStaticCounter1 = new SharedStaticVarReadWriteSafe();
SharedStaticVarReadWriteSafe safeStaticCounter2 = new SharedStaticVarReadWriteSafe();
int numThreads = 1000;
CountDownLatch latch = new CountDownLatch(numThreads);
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < numThreads; i++) {
executor.submit(() -> {
if (Math.random() > 0.5) {
safeStaticCounter1.incrementStaticAtomic();
} else {
safeStaticCounter2.incrementStaticAtomic();
}
latch.countDown();
});
}
latch.await();
executor.shutdown();
System.out.println("Safe static counter (Atomic) final count: " + getAtomicStaticCount() + " (Expected " + numThreads + ")");
}
}
// --- 局部变量是否线程安全? ---
// 1. 局部变量是线程安全的 (指变量本身,如基本类型或引用)
static class LocalVarIsThreadSafe {
public void process() {
int localPrimitive = 0; // 局部基本类型变量
String localReference = "start"; // 局部引用变量,指向一个不可变对象
for (int i = 0; i < 5; i++) {
localPrimitive++;
localReference = localReference + "-" + i; // 每次都会创建一个新的String对象
}
// 每个线程都有自己的 localPrimitive 和 localReference 副本
System.out.println(Thread.currentThread().getName() + ": localPrimitive = " + localPrimitive +
", localReference ends with " + localReference.substring(localReference.length()-2));
}
public static void demo() throws InterruptedException {
System.out.println("\n--- 局部变量本身是线程安全的 ---");
LocalVarIsThreadSafe processor = new LocalVarIsThreadSafe();
Thread t1 = new Thread(() -> processor.process(), "T1_LocalVar");
Thread t2 = new Thread(() -> processor.process(), "T2_LocalVar");
t1.start();
t2.start();
t1.join();
t2.join();
// 每个线程都能正确完成自己的计算,输出都是 localPrimitive = 5, localReference ends with -4
}
}
// 2. 但局部变量引用的对象则未必
// 2.1 如果该对象没有逃离方法的作用范围, 它是线程安全的
static class LocalObjectRefNotEscaped {
public void processList() {
List<String> localList = new ArrayList<>(); // 局部变量引用一个只在方法内使用的对象
for (int i = 0; i < 3; i++) {
localList.add(Thread.currentThread().getName() + "_val_" + i);
}
System.out.println(Thread.currentThread().getName() + ": Local list size = " + localList.size() + ", content: " + localList);
// localList 没有被返回,没有赋值给成员变量或静态变量,没有传递给其他可能共享它的方法
// 因此,这个 ArrayList 实例只被当前线程访问,是线程安全的。
}
public static void demo() throws InterruptedException {
System.out.println("\n--- 局部变量引用的对象 - 没有逃离方法范围 ---");
LocalObjectRefNotEscaped processor = new LocalObjectRefNotEscaped();
Thread t1 = new Thread(() -> processor.processList(), "T1_LocalObjNoEscape");
Thread t2 = new Thread(() -> processor.processList(), "T2_LocalObjNoEscape");
t1.start();
t2.start();
t1.join();
t2.join();
// 每个线程都有自己的 ArrayList 实例
}
}
// 2.2 如果该对象逃离方法的作用范围, 需要考虑线程安全
static class LocalObjectRefEscaped {
// 共享的列表,用于演示对象逃逸后的问题
private static final List<String> SHARED_LIST_UNSAFE = new ArrayList<>(); // 非线程安全的List
private static final List<String> SHARED_LIST_SAFE = new Vector<>(); // 线程安全的List (或 Collections.synchronizedList)
public void addToListUnsafe(String value) {
StringBuilder localSb = new StringBuilder(value); // 局部变量,引用的对象是新的
// ... 做一些操作 ...
localSb.append("_processed_by_").append(Thread.currentThread().getName());
SHARED_LIST_UNSAFE.add(localSb.toString()); // 对象 (toString()的结果) 逃逸到了共享列表
// 如果多个线程同时操作 SHARED_LIST_UNSAFE (非线程安全),可能出问题。
// 这里的 'localSb.toString()' 产生的新String是不可变的,所以添加到List里是安全的。
// 更危险的逃逸是把 localSb 本身 (如果它是可变的且被后续修改) 或一个可变集合给外部。
}
public void addToListSafe(String value) {
StringBuilder localSb = new StringBuilder(value);
localSb.append("_processed_by_").append(Thread.currentThread().getName());
SHARED_LIST_SAFE.add(localSb.toString()); // Vector是线程安全的
}
// 演示一个更典型的“逃逸”导致问题的场景
public List<String> createAndReturnList() {
List<String> localList = new ArrayList<>(); // 局部创建
localList.add("item_from_" + Thread.currentThread().getName());
return localList; // localList 逃逸了!
}
// 如果把 createAndReturnList 返回的 list 赋值给一个共享变量,并且多个线程修改它,就会有问题
public static List<String> globallyAccessibleList; // 用于演示逃逸后的共享
public static void demo() throws InterruptedException {
System.out.println("\n--- 局部变量引用的对象 - 逃离方法范围 ---");
LocalObjectRefEscaped processor = new LocalObjectRefEscaped();
int numThreads = 100;
CountDownLatch latchUnsafe = new CountDownLatch(numThreads);
CountDownLatch latchSafe = new CountDownLatch(numThreads);
CountDownLatch latchEscaped = new CountDownLatch(numThreads);
ExecutorService executor = Executors.newFixedThreadPool(10);
System.out.println("--- 2.2.a 逃逸到非线程安全共享集合 (ArrayList add本身非线程安全) ---");
SHARED_LIST_UNSAFE.clear();
for (int i = 0; i < numThreads; i++) {
final int val = i;
executor.submit(() -> {
processor.addToListUnsafe("unsafe_item_" + val);
latchUnsafe.countDown();
});
}
latchUnsafe.await();
// ArrayList 的 add 操作本身如果并发可能导致内部数组扩容问题等,或者丢失元素。
// 虽然我们添加的是String (不可变),但ArrayList本身状态的修改不是线程安全的。
System.out.println("SHARED_LIST_UNSAFE size: " + SHARED_LIST_UNSAFE.size() + " (Expected " + numThreads + ", may vary or throw CMEs in extreme cases)");
System.out.println("\n--- 2.2.b 逃逸到线程安全共享集合 ---");
SHARED_LIST_SAFE.clear();
for (int i = 0; i < numThreads; i++) {
final int val = i;
executor.submit(() -> {
processor.addToListSafe("safe_item_" + val);
latchSafe.countDown();
});
}
latchSafe.await();
System.out.println("SHARED_LIST_SAFE size: " + SHARED_LIST_SAFE.size() + " (Expected " + numThreads + ")");
System.out.println("\n--- 2.2.c 局部对象通过返回值逃逸,并被共享和修改 (不安全) ---");
// 这个例子稍微复杂一点,演示真正的"对象逃逸后被不安全地共享"
// 我们让每个线程创建一个 List,然后尝试把这个 list "合并"到一个全局的 list 中。
// 如果全局 list 是 ArrayList,并且多个线程同时 addAll,就会出问题。
globallyAccessibleList = new ArrayList<>(); // 非线程安全的全局 list
for (int i = 0; i < numThreads; i++) {
executor.submit(() -> {
List<String> returnedList = processor.createAndReturnList(); // localList 逃逸了
// 现在多个线程可能同时修改 globallyAccessibleList
// globallyAccessibleList.addAll(returnedList); // 这是不安全的
synchronized (LocalObjectRefEscaped.class) { // 必须加锁保护共享的 globallyAccessibleList
globallyAccessibleList.addAll(returnedList);
}
latchEscaped.countDown();
});
}
latchEscaped.await();
System.out.println("GloballyAccessibleList (escaped) size: " + globallyAccessibleList.size() + " (Expected " + numThreads + ")");
executor.shutdown();
}
}
public static void main(String[] args) throws InterruptedException {
MemberVarNotShared.demo();
SharedMemberVarReadOnly.demo();
SharedMemberVarReadWriteUnsafe.demo();
SharedMemberVarReadWriteSafe.demo();
SharedStaticVarReadOnly.demo();
SharedStaticVarReadWriteUnsafe.demo();
SharedStaticVarReadWriteSafe.demo();
LocalVarIsThreadSafe.demo();
LocalObjectRefNotEscaped.demo();
LocalObjectRefEscaped.demo();
System.out.println("\n--- All Demos Completed ---");
}
}