多线程同步打标记的几种实现方案

以下是各种多线程同步打标记的实现方案,适用于不同的使用场景:

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. 使用建议

选择策略

  1. 简单标记,高并发读取AtomicBooleanvolatile+ 双重检查锁

  2. 复杂标记逻辑ReentrantLocksynchronized

  3. 读写分离ReadWriteLock

  4. 线程数量控制Semaphore

  5. 线程协调CountDownLatchCyclicBarrierPhaser

  6. 异步任务链CompletableFuture

  7. 分布式环境:Redis分布式锁、ZooKeeper

  8. 高性能场景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();  // 确保解锁
        }
    }
}

总结

选择多线程同步打标记方案时,需要考虑:

  1. 性能需求:高并发场景优先考虑无锁(CAS)实现

  2. 复杂度 :简单场景用 AtomicBoolean,复杂场景用锁

  3. 协调需求 :需要线程协调时用 CountDownLatch等工具

  4. 可扩展性:考虑未来可能的变化

  5. 维护性:代码要清晰易懂

在大多数情况下,推荐使用:

  • 简单标记:AtomicBoolean

  • 复杂逻辑:ReentrantLock

  • 线程协调:CountDownLatch/CyclicBarrier

  • 异步编程:CompletableFuture

相关推荐
Mr_Xuhhh2 小时前
递归之美:合并两个有序链表的优雅解法
java·开发语言
bluebonnet272 小时前
【Python】一些PEP提案(五):注解的延迟求值
开发语言·python
InfinteJustice2 小时前
mysql如何排查插件加载失败原因_mysql plugin目录与权限核对
jvm·数据库·python
qq_189807032 小时前
Go语言怎么连接Elasticsearch_Go语言Elasticsearch教程【收藏】
jvm·数据库·python
橙露2 小时前
Python 操作 MongoDB:非关系型数据查询与分析
开发语言·python·mongodb
小魏小魏我们去那里呀2 小时前
Java2Flowchart:一款把 Java 方法一键转换成 Mermaid 流程图的 IntelliJ 插件
java·ide·intellij-idea
小江的记录本2 小时前
【RAG】RAG检索增强生成(核心架构、全流程、RAG优化方案、常见问题与解决方案)
java·前端·人工智能·后端·python·机器学习·架构
迷藏4942 小时前
**TiDB 在高并发场景下的性能优化实战:从慢查询到极致吞吐的跃迁**在现代分布式系统中,数据库不仅是数据存储的
java·数据库·python·性能优化·tidb
m0_678485452 小时前
如何自动同步SQL异构表数据_利用触发器实现实时数据复制
jvm·数据库·python