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

Java线程同步疑惑:仅同步线程创建而非执行的含义解析

理解“同步线程创建而非执行”的含义

1. 代码中的同步仅管控任务提交过程

你代码里的synchronized (manager)块,只包裹了service.submit(...)的循环调用。这里的同步仅仅保证10次任务提交动作是串行执行的:每次submit都会等上一次完成后再执行,不会出现多个线程同时往线程池里塞任务的情况。但这只是“创建/安排线程任务”的动作被同步了,和任务真正的执行逻辑完全没关系。

2. 线程执行过程完全不受当前同步约束

线程池收到任务后,会调度空闲线程去执行() -> manager.incrementAndReport()这个Lambda逻辑。这些线程的执行是独立且并行的:

  • ++sheepCount本质是三步非原子操作:读取当前值、加1、写回新值。多个线程同时执行时,会出现“同时读同一个值,加1后写回相同结果”的竞态条件,导致计数错误。
  • System.out.print也不是线程安全的方法,多个线程同时调用会让输出顺序混乱。

直白点说:你同步的是“给工人派活的流程”(逐个派活),但派完活后,所有工人会同时动手抢着改同一个计数器,自然会出问题。

3. 正确的同步方式(针对任务执行)

要解决线程安全问题,需要同步任务执行的核心逻辑,而非任务提交过程,常见的三种方式:

方式一:给方法添加同步修饰符

public class SheepManager {
    private int sheepCount = 0;

    // 给方法加同步,保证同一时间只有一个线程能执行该方法
    private synchronized void incrementAndReport() {
        System.out.print((++sheepCount)+" ");
    }

    public static void main(String[] args) {
        ExecutorService service = null;
        try {
            service = Executors.newFixedThreadPool(20);
            SheepManager manager = new SheepManager();
            for(int i=0; i<10; i++)
                service.submit(() -> manager.incrementAndReport());
        } finally {
            if(service != null) service.shutdown();
        }
    }
}

方式二:在方法内部针对共享变量加锁

private void incrementAndReport() {
    // 仅对计数和输出的核心逻辑加锁,缩小同步范围
    synchronized (this) {
        System.out.print((++sheepCount)+" ");
    }
}

方式三:用原子类保证计数操作的原子性

import java.util.concurrent.atomic.AtomicInteger;

public class SheepManager {
    // 用原子类替代普通int,incrementAndGet是原子操作
    private AtomicInteger sheepCount = new AtomicInteger(0);

    private void incrementAndReport() {
        System.out.print(sheepCount.incrementAndGet()+" ");
    }

    // main方法同前,无需额外同步
}

内容的提问来源于stack exchange,提问作者Thoại Kiều

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:46:21