Appearance
08_线程安全实现方法.md
实现线程安全的方法可以归纳为以下几种主要策略:互斥同步、非阻塞同步、线程限制和无同步方案。每种策略都有其适用场景和具体实现方式。下面详细介绍每种策略及其示例代码。
- 互斥同步(Mutual Exclusion Synchronization)
- 互斥同步通过锁(如 synchronized 和 ReentrantLock)来确保同一时刻只有一个线程可以访问共享资源,从而避免数据竞争。
java
public class SynchronizedExample {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
public static void main(String[] args) {
SynchronizedExample example = new SynchronizedExample();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + example.getCount());
}
}
- 非阻塞同步(Non-blocking Synchronization)
- 非阻塞同步通过原子操作和 CAS(Compare-And-Swap)技术来实现线程安全,避免了线程阻塞。Java 提供了 java.util.concurrent.atomic 包来支持非阻塞同步。
java
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicExample {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
public static void main(String[] args) {
AtomicExample example = new AtomicExample();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + example.getCount());
}
}
在这个例子中,AtomicInteger 提供了原子操作 incrementAndGet,确保了 count 变量的线程安全。 3. 线程限制(Thread Confinement)
- 线程限制通过将数据限制在单个线程中访问,避免了共享数据的并发访问问题。线程限制是最简单的线程安全策略,因为它完全避免了多线程访问共享资源。
java
public class ThreadConfinementExample {
public static void main(String[] args) {
Runnable task = () -> {
int count = 0; // 局部变量,线程限制
for (int i = 0; i < 1000; i++) {
count++;
}
System.out.println("Final count: " + count);
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在这个例子中,count 变量是局部变量,只能被各自的线程访问,因此不存在并发访问问题。
- 无同步方案(No Synchronization)
- 无同步方案通过使用不可变对象(immutable objects)或将数据分发到各个线程中,避免了同步需求。常见的方式有使用不可变类和线程本地存储(Thread Local Storage)。
java
public final class ImmutableExample {
private final int count;
public ImmutableExample(int count) {
this.count = count;
}
public ImmutableExample increment() {
return new ImmutableExample(this.count + 1);
}
public int getCount() {
return count;
}
public static void main(String[] args) {
ImmutableExample example = new ImmutableExample(0);
ImmutableExample newExample = example.increment();
System.out.println("Original count: " + example.getCount());
System.out.println("New count: " + newExample.getCount());
}
}
在这个例子中,ThreadLocal 确保每个线程都有独立的 count 变量实例,避免了并发访问问题。
总结
- 互斥同步:通过锁机制(如 synchronized 和 ReentrantLock)确保线程对共享资源的互斥访问。
- 非阻塞同步:通过原子操作和 CAS 技术实现线程安全,避免线程阻塞。
- 线程限制:通过将数据限制在单个线程中访问,避免了共享数据的并发访问问题。
- 无同步方案:通过使用不可变对象或线程本地存储,避免了同步需求。