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
相关产品推荐
相关产品推荐

