You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在使用ExecutorService的Java多线程应用中处理与避免竞态条件?

如何在使用ExecutorService的Java多线程应用中处理与避免竞态条件?

嘿,我来帮你搞定这个竞态条件的问题!你现在的代码里,10个线程通过线程池调用sharedResource.updateData(),如果这个方法里有读写共享变量的操作却没加任何同步控制,多个线程肯定会互相干扰,导致数据错乱——这就是你遇到的竞态条件。下面给你几个实用的解决方案,适配不同的场景:

1. 给共享方法/代码块加同步锁(最直接的方案)

如果你的updateData方法里的操作需要整体同步,最省事的就是用synchronized关键字修饰方法,它会给当前SharedResource对象自动加锁,同一时间只有一个线程能执行这个方法:

class SharedResource {
    private int data = 0;

    // 用synchronized修饰方法,保证线程安全
    public synchronized void updateData() {
        // 这里放你原来的更新逻辑,比如data累加
        data++;
        System.out.println("Updated data to: " + data);
    }
}

要是只有方法里的某一段代码需要同步,也可以用同步块,建议用专门的私有锁对象,避免外部代码意外干扰:

class SharedResource {
    private int data = 0;
    // 专门的锁对象,只在内部使用
    private final Object lock = new Object();

    public void updateData() {
        // 这里可以放不需要同步的代码...
        synchronized(lock) {
            data++;
            System.out.println("Updated data to: " + data);
        }
        // 这里也可以放不需要同步的代码...
    }
}

2. 用原子类处理简单数值操作(更高效的方案)

如果你的共享资源是简单的数值类型(比如计数、累加),用java.util.concurrent.atomic包下的原子类会更高效——它用硬件级别的CAS(比较并交换)机制实现线程安全,不需要阻塞线程:

import java.util.concurrent.atomic.AtomicInteger;

class SharedResource {
    // 用AtomicInteger替代普通int,自带线程安全的操作方法
    private final AtomicInteger data = new AtomicInteger(0);

    public void updateData() {
        // 原子操作,不需要手动加锁
        int newData = data.incrementAndGet();
        System.out.println("Updated data to: " + newData);
    }
}

这种方案比synchronized性能更好,适合简单的数值更新场景,比如统计任务执行次数、累加计数之类的。

3. 用ReentrantLock实现灵活同步(复杂场景适配)

如果你的同步逻辑比较复杂(比如需要尝试获取锁、超时等待、多条件判断),可以用ReentrantLock,它比synchronized更灵活,支持更多高级特性:

import java.util.concurrent.locks.ReentrantLock;

class SharedResource {
    private int data = 0;
    private final ReentrantLock lock = new ReentrantLock();

    public void updateData() {
        // 手动加锁
        lock.lock();
        try {
            // 这里放需要同步的更新逻辑
            data++;
            System.out.println("Updated data to: " + data);
        } finally {
            // 必须在finally块里释放锁,避免异常导致锁无法释放
            lock.unlock();
        }
    }
}

注意:用ReentrantLock一定要记得用try-finally包裹同步代码,确保锁能被正确释放,不然会导致线程池里的线程被阻塞,甚至死锁。

额外小提示

如果你的共享资源是集合类,别自己手动加锁,直接用java.util.concurrent包下的并发集合就行,比如ConcurrentHashMap、CopyOnWriteArrayList,这些集合本身就实现了线程安全,性能也比普通集合加锁好很多。

备注:内容来源于stack exchange,提问作者Harini Ramkarthik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 10:24:28