以下是各种多线程同步打标记的实现方案,适用于不同的使用场景:
1. 原子标记(AtomicBoolean/AtomicInteger)
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicMarker {
// 使用AtomicBoolean作为标记
private final AtomicBoolean isDone = new AtomicBoolean(false);
private final AtomicInteger counter = new AtomicInteger(0);
/**
* 方法1: 使用AtomicBoolean标记
*/
public void atomicBooleanExample() {
// 线程安全地设置标记
if (isDone.compareAndSet(false, true)) {
System.out.println("标记被设置成功,当前线程:" + Thread.currentThread().getName());
} else {
System.out.println("标记已被其他线程设置");
}
}
/**
* 方法2: 使用AtomicInteger计数标记
*/
public void atomicIntegerExample() {
// 递增计数
int count = counter.incrementAndGet();
if (count == 1) {
System.out.println("第一个完成的线程:" + Thread.currentThread().getName());
} else if (count == 5) {
System.out.println("第5个线程完成,达到阈值");
}
}
}
2. 同步锁标记(Synchronized)
public class SynchronizedMarker {
private volatile boolean isMarked = false;
private final Object lock = new Object();
/**
* 使用synchronized同步
*/
public void synchronizedMark() {
synchronized (lock) {
if (!isMarked) {
// 模拟耗时操作
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
isMarked = true;
System.out.println(Thread.currentThread().getName() + " 设置了标记");
} else {
System.out.println(Thread.currentThread().getName() + " 发现标记已设置");
}
}
}
/**
* 双重检查锁定模式(DCL)
*/
public void doubleCheckLocking() {
if (!isMarked) { // 第一次检查
synchronized (lock) {
if (!isMarked) { // 第二次检查
isMarked = true;
System.out.println(Thread.currentThread().getName() + " 设置了标记(DCL)");
}
}
}
}
}
3. 可重入锁标记(ReentrantLock)
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockMarker {
private boolean isMarked = false;
private final Lock lock = new ReentrantLock();
/**
* 基本ReentrantLock使用
*/
public void reentrantLockMark() {
lock.lock();
try {
if (!isMarked) {
isMarked = true;
System.out.println(Thread.currentThread().getName() + " 设置了标记");
}
} finally {
lock.unlock(); // 必须放在finally中
}
}
/**
* 尝试获取锁,可设置超时
*/
public void tryLockMark() {
boolean acquired = false;
try {
// 尝试获取锁,最多等待1秒
acquired = lock.tryLock(1, TimeUnit.SECONDS);
if (acquired) {
if (!isMarked) {
isMarked = true;
System.out.println(Thread.currentThread().getName() + " 成功设置标记");
}
} else {
System.out.println(Thread.currentThread().getName() + " 获取锁超时");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
if (acquired) {
lock.unlock();
}
}
}
}
4. 读写锁标记(ReadWriteLock)
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockMarker {
private boolean isMarked = false;
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
/**
* 读标记 - 多个线程可同时读
*/
public boolean readMark() {
rwLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " 读取标记: " + isMarked);
return isMarked;
} finally {
rwLock.readLock().unlock();
}
}
/**
* 写标记 - 只有一个线程可写
*/
public void writeMark(boolean newValue) {
rwLock.writeLock().lock();
try {
isMarked = newValue;
System.out.println(Thread.currentThread().getName() + " 设置标记为: " + newValue);
} finally {
rwLock.writeLock().unlock();
}
}
}
5. 信号量标记(Semaphore)
import java.util.concurrent.Semaphore;
public class SemaphoreMarker {
// 信号量控制同时执行的线程数
private final Semaphore semaphore = new Semaphore(1); // 只允许1个线程执行
private volatile boolean isMarked = false;
public void semaphoreMark() {
try {
// 获取许可
semaphore.acquire();
if (!isMarked) {
// 模拟耗时操作
Thread.sleep(1000);
isMarked = true;
System.out.println(Thread.currentThread().getName() + " 设置了标记");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
semaphore.release();
}
}
/**
* 使用信号量控制N个标记
*/
public void limitedMarks(int limit) {
// 只允许limit个线程设置标记
Semaphore limitedSemaphore = new Semaphore(limit);
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
if (limitedSemaphore.tryAcquire(1, TimeUnit.SECONDS)) {
System.out.println(Thread.currentThread().getName() + " 获得标记许可");
Thread.sleep(500);
} else {
System.out.println(Thread.currentThread().getName() + " 未获得标记许可");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
limitedSemaphore.release();
}
}).start();
}
}
}
6. 倒计时门闩标记(CountDownLatch)
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class CountDownLatchMarker {
private final CountDownLatch latch = new CountDownLatch(1);
private volatile boolean isMarked = false;
public void countDownLatchExample() {
// 线程A等待标记
new Thread(() -> {
try {
System.out.println("线程A等待标记...");
latch.await(); // 等待门闩打开
System.out.println("线程A收到标记,继续执行");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
// 线程B设置标记
new Thread(() -> {
try {
Thread.sleep(2000); // 模拟工作
isMarked = true;
latch.countDown(); // 打开门闩
System.out.println("线程B设置了标记");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
/**
* 多个线程等待一个标记
*/
public void multipleWaiters(int waiterCount) {
CountDownLatch startLatch = new CountDownLatch(1);
CountDownLatch endLatch = new CountDownLatch(waiterCount);
for (int i = 0; i < waiterCount; i++) {
int threadId = i;
new Thread(() -> {
try {
System.out.println("线程" + threadId + "等待开始信号");
startLatch.await(); // 所有线程等待开始信号
// 执行任务
System.out.println("线程" + threadId + "开始工作");
Thread.sleep(1000);
endLatch.countDown(); // 完成任务
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
// 主线程控制开始
new Thread(() -> {
try {
Thread.sleep(2000);
System.out.println("发送开始信号");
startLatch.countDown(); // 开始所有线程
endLatch.await(); // 等待所有线程完成
System.out.println("所有线程完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
7. 循环栅栏标记(CyclicBarrier)
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierMarker {
/**
* 所有线程到达栅栏后执行特定操作
*/
public void cyclicBarrierExample(int threadCount) {
CyclicBarrier barrier = new CyclicBarrier(threadCount, () -> {
// 所有线程到达后执行
System.out.println("所有线程都已到达,执行标记操作");
});
for (int i = 0; i < threadCount; i++) {
int threadId = i;
new Thread(() -> {
try {
System.out.println("线程" + threadId + "开始工作");
Thread.sleep(threadId * 1000L); // 模拟不同耗时
System.out.println("线程" + threadId + "到达栅栏");
barrier.await(); // 等待其他线程
System.out.println("线程" + threadId + "继续执行");
} catch (InterruptedException | BrokenBarrierException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
}
8. 阶段器标记(Phaser)
import java.util.concurrent.Phaser;
public class PhaserMarker {
/**
* 更灵活的栅栏
*/
public void phaserExample() {
Phaser phaser = new Phaser(3) { // 注册3个线程
@Override
protected boolean onAdvance(int phase, int registeredParties) {
// 阶段完成时执行
System.out.println("阶段 " + phase + " 完成");
return phase >= 2 || registeredParties == 0; // 终止条件
}
};
for (int i = 0; i < 3; i++) {
int threadId = i;
new Thread(() -> {
System.out.println("线程" + threadId + "到达阶段0");
phaser.arriveAndAwaitAdvance(); // 到达并等待
System.out.println("线程" + threadId + "到达阶段1");
phaser.arriveAndAwaitAdvance();
System.out.println("线程" + threadId + "完成所有阶段");
phaser.arriveAndDeregister(); // 到达并注销
}).start();
}
}
}
9. CompletableFuture 标记
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CompletableFutureMarker {
private final ExecutorService executor = Executors.newFixedThreadPool(4);
/**
* 使用CompletableFuture进行标记
*/
public void completableFutureExample() throws ExecutionException, InterruptedException {
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
System.out.println("任务1执行");
}, executor);
CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
System.out.println("任务2执行");
}, executor);
CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {
System.out.println("任务3执行");
}, executor);
// 等待所有任务完成
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);
// 所有任务完成后执行
allFutures.thenRun(() -> {
System.out.println("所有任务完成,打标记");
}).join(); // 等待完成
executor.shutdown();
}
/**
* 异步回调链
*/
public void asyncChain() {
CompletableFuture.supplyAsync(() -> {
System.out.println("阶段1: 获取数据");
return "data";
}).thenApply(data -> {
System.out.println("阶段2: 处理数据");
return data + "-processed";
}).thenAccept(result -> {
System.out.println("阶段3: 消费结果: " + result);
}).thenRun(() -> {
System.out.println("阶段4: 完成标记");
});
}
}
10. 分布式场景下的标记(Redisson分布式锁)
import org.redisson.Redisson;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class DistributedMarker {
private RedissonClient redisson;
public DistributedMarker() {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379");
redisson = Redisson.create(config);
}
/**
* 分布式锁标记
*/
public void distributedLockMark(String key) {
RLock lock = redisson.getLock(key);
try {
// 尝试获取锁,等待10秒,锁有效期30秒
boolean locked = lock.tryLock(10, 30, TimeUnit.SECONDS);
if (locked) {
try {
// 执行业务逻辑
System.out.println("获取分布式锁成功,线程: " + Thread.currentThread().getName());
Thread.sleep(1000);
} finally {
lock.unlock();
System.out.println("释放分布式锁");
}
} else {
System.out.println("获取分布式锁失败");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
/**
* 分布式原子计数器
*/
public void distributedAtomicCounter() {
RAtomicLong counter = redisson.getAtomicLong("distributedCounter");
// 原子递增
long count = counter.incrementAndGet();
if (count == 1) {
System.out.println("第一个线程获取到标记");
} else if (count <= 5) {
System.out.println("第" + count + "个线程");
} else {
System.out.println("超过限制,当前计数: " + count);
}
}
public void shutdown() {
if (redisson != null) {
redisson.shutdown();
}
}
}
11. 组合模式:线程安全的标记管理器
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MarkManager {
// 线程安全的标记存储
private final Map<String, MarkInfo> markMap = new ConcurrentHashMap<>();
// 标记信息
static class MarkInfo {
private final AtomicBoolean marked = new AtomicBoolean(false);
private final Lock lock = new ReentrantLock();
private volatile long markTime = 0;
public boolean mark() {
if (marked.compareAndSet(false, true)) {
markTime = System.currentTimeMillis();
return true;
}
return false;
}
public boolean isMarked() {
return marked.get();
}
public long getMarkTime() {
return markTime;
}
}
/**
* 获取或创建标记
*/
public MarkInfo getMark(String key) {
return markMap.computeIfAbsent(key, k -> new MarkInfo());
}
/**
* 安全地设置标记
*/
public boolean safeMark(String key) {
MarkInfo mark = getMark(key);
mark.lock.lock();
try {
if (!mark.isMarked()) {
// 执行一些初始化操作
System.out.println("初始化标记: " + key);
// 设置标记
return mark.mark();
}
return false;
} finally {
mark.lock.unlock();
}
}
/**
* 批量标记操作
*/
public void batchMark(String... keys) {
// 先尝试获取所有锁(防止死锁)
for (String key : keys) {
MarkInfo mark = getMark(key);
mark.lock.lock();
}
try {
// 检查所有标记是否可用
boolean allAvailable = true;
for (String key : keys) {
if (getMark(key).isMarked()) {
allAvailable = false;
break;
}
}
if (allAvailable) {
// 批量设置标记
for (String key : keys) {
getMark(key).mark();
System.out.println("设置标记: " + key);
}
}
} finally {
// 按相同顺序释放锁
for (String key : keys) {
getMark(key).lock.unlock();
}
}
}
}
12. 性能测试和比较
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
public class MarkerBenchmark {
private static final int THREAD_COUNT = 100;
private static final int ITERATIONS = 10000;
public static void main(String[] args) throws InterruptedException {
System.out.println("=== 标记性能测试 ===");
testAtomicBoolean();
testSynchronized();
testReentrantLock();
testVolatile();
}
private static void testAtomicBoolean() throws InterruptedException {
AtomicBoolean marker = new AtomicBoolean(false);
ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
CountDownLatch latch = new CountDownLatch(THREAD_COUNT);
long start = System.currentTimeMillis();
for (int i = 0; i < THREAD_COUNT; i++) {
executor.submit(() -> {
for (int j = 0; j < ITERATIONS; j++) {
if (marker.compareAndSet(false, true)) {
// 模拟标记操作
marker.set(false);
}
}
latch.countDown();
});
}
latch.await();
long time = System.currentTimeMillis() - start;
System.out.printf("AtomicBoolean: %d ms%n", time);
executor.shutdown();
}
private static void testSynchronized() throws InterruptedException {
Object lock = new Object();
boolean marked = false;
ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
CountDownLatch latch = new CountDownLatch(THREAD_COUNT);
long start = System.currentTimeMillis();
for (int i = 0; i < THREAD_COUNT; i++) {
executor.submit(() -> {
for (int j = 0; j < ITERATIONS; j++) {
synchronized (lock) {
if (!marked) {
marked = true;
marked = false;
}
}
}
latch.countDown();
});
}
latch.await();
long time = System.currentTimeMillis() - start;
System.out.printf("Synchronized: %d ms%n", time);
executor.shutdown();
}
private static void testReentrantLock() throws InterruptedException {
ReentrantLock lock = new ReentrantLock();
boolean marked = false;
ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
CountDownLatch latch = new CountDownLatch(THREAD_COUNT);
long start = System.currentTimeMillis();
for (int i = 0; i < THREAD_COUNT; i++) {
executor.submit(() -> {
for (int j = 0; j < ITERATIONS; j++) {
lock.lock();
try {
if (!marked) {
marked = true;
marked = false;
}
} finally {
lock.unlock();
}
}
latch.countDown();
});
}
latch.await();
long time = System.currentTimeMillis() - start;
System.out.printf("ReentrantLock: %d ms%n", time);
executor.shutdown();
}
private static void testVolatile() throws InterruptedException {
volatile boolean marked = false;
ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
CountDownLatch latch = new CountDownLatch(THREAD_COUNT);
long start = System.currentTimeMillis();
for (int i = 0; i < THREAD_COUNT; i++) {
executor.submit(() -> {
for (int j = 0; j < ITERATIONS; j++) {
// volatile不保证原子性,仅用于测试
if (!marked) {
marked = true;
marked = false;
}
}
latch.countDown();
});
}
latch.await();
long time = System.currentTimeMillis() - start;
System.out.printf("Volatile: %d ms%n", time);
executor.shutdown();
}
}
13. 使用建议
选择策略
-
简单标记,高并发读取 :
AtomicBoolean或volatile+ 双重检查锁 -
复杂标记逻辑 :
ReentrantLock或synchronized -
读写分离 :
ReadWriteLock -
线程数量控制 :
Semaphore -
线程协调 :
CountDownLatch、CyclicBarrier、Phaser -
异步任务链 :
CompletableFuture -
分布式环境:Redis分布式锁、ZooKeeper
-
高性能场景 :
AtomicBoolean>ReentrantLock>synchronized
最佳实践
public class MarkingBestPractices {
// 1. 明确标记的可见性和原子性需求
private volatile boolean flag1; // 可见性
private AtomicBoolean flag2; // 原子性
// 2. 使用合适的锁粒度
private final Object fineGrainedLock = new Object(); // 细粒度锁
private static final Object coarseGrainedLock = new Object(); // 粗粒度锁
// 3. 避免死锁
public void avoidDeadlock(Lock lock1, Lock lock2) {
while (true) {
if (lock1.tryLock()) {
try {
if (lock2.tryLock()) {
try {
// 成功获取两把锁
return;
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
// 重试前稍作等待
try {
Thread.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
// 4. 资源清理
public void cleanResourceExample() {
Lock lock = new ReentrantLock();
try {
lock.lock();
// 执行业务逻辑
} finally {
lock.unlock(); // 确保解锁
}
}
}
总结
选择多线程同步打标记方案时,需要考虑:
-
性能需求:高并发场景优先考虑无锁(CAS)实现
-
复杂度 :简单场景用
AtomicBoolean,复杂场景用锁 -
协调需求 :需要线程协调时用
CountDownLatch等工具 -
可扩展性:考虑未来可能的变化
-
维护性:代码要清晰易懂
在大多数情况下,推荐使用:
-
简单标记:
AtomicBoolean -
复杂逻辑:
ReentrantLock -
线程协调:
CountDownLatch/CyclicBarrier -
异步编程:
CompletableFuture