Java Socket并发写入问题:多线程连接下变量计数未达预期值
问题根源:竞态条件(Race Condition)
这是多线程环境下非常典型的共享资源同步问题!你的两个客户端线程在操作同一个全局变量时,读-改-写这三个步骤不是原子操作,导致了互相覆盖的情况:
比如线程A刚读到变量值为1,还没来得及把递增后的2写回去,线程B也读到了这个1,然后两个线程都把变量改成2并输出,相当于白白浪费了一次递增操作。这就是为什么服务器输出会是1 1 2 2 … 10 10,最终变量值只有10而不是预期的20。
解决方法
只要保证对共享变量的递增操作是原子性的(要么完整执行,要么不执行,中间不会被其他线程打断),就能解决这个问题,下面是两种常用的方案:
1. 使用synchronized同步锁
方案一:同步方法
如果你的递增逻辑是封装在一个方法里的,直接给方法加上synchronized关键字:
// 假设共享变量是静态全局变量 private static int count = 0; // 同步的递增方法 public synchronized static void increment() { count++; System.out.print(count + " "); }
每个线程调用这个方法时,必须先获取锁,同一时间只有一个线程能执行方法里的逻辑,从根本上避免了同时读写的冲突。
方案二:同步代码块
如果不想给整个方法加锁(比如方法里还有其他不需要同步的逻辑),可以只在操作共享变量的代码块上加锁:
// 用类对象作为锁(因为变量是静态的,属于类级别) synchronized (YourServerClass.class) { count++; System.out.print(count + " "); }
2. 使用原子类(更轻量级)
Java的java.util.concurrent.atomic包提供了一系列原子操作类,专门解决这种简单的共享变量原子操作问题,不需要手动加锁:
// 用AtomicInteger代替普通int private static AtomicInteger count = new AtomicInteger(0); // 在线程中调用原子递增方法 int newValue = count.incrementAndGet(); System.out.print(newValue + " ");
incrementAndGet()方法本身就是原子性的,底层通过CAS(Compare-And-Swap)机制实现,比synchronized的性能更好,适合这种简单的递增场景。
验证效果
用上面任意一种方案修改后,服务器的输出会变成1 2 3 4 … 19 20,最终变量值也会正确达到20,因为每一次递增操作都被完整执行,不会被其他线程打断。
内容的提问来源于stack exchange,提问作者user2962142
相关产品推荐
相关产品推荐

