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

为何Counting类count值为0而非预期20?如何修正该多线程问题

问题分析与解决方案

哈哈,这个问题我刚学Java多线程的时候也踩过一模一样的坑!咱们拆解下问题出在哪,以及怎么拿到预期的20:

你的代码核心错误

  • 每个线程操作的是独立的计数器实例:mulA和mulB的run()方法里都各自new Counting(),这意味着两个线程完全在操作不同的Counting对象,各自把自己的计数器加到10,但这两个实例的状态完全和主线程最后打印的对象没关系。
  • 最后打印的是全新的空计数器:main方法最后new Counting()出来的obj4是一个全新的实例,它的count初始值就是0,所以打印0是必然的结果。
  • 虽然counter()方法加了synchronized,但这个锁是针对对象实例的,不同实例的锁互不影响,不过这里的核心问题根本不是锁,而是实例不共享。

修正方案:让两个线程共享同一个Counting实例

要拿到20,必须让两个线程操作同一个Counting对象,这样它们的累加才会作用在同一个count变量上。下面是两种常见的修正方式:

方式一:给Runnable实现类传入共享的Counting实例

修改你的代码,让mulA和mulB接收外部传入的Counting对象,而不是自己创建(还可以合并两个重复的Runnable类,减少冗余):

class Counting{
    public int count ;
    public synchronized void counter(){
        count = count + 1;
    }
}

// 合并成通用的Runnable实现,没必要写两个几乎一样的类
class CounterRunnable implements Runnable{
    private Counting countingObj; // 持有共享的计数器实例

    // 通过构造函数传入共享实例
    public CounterRunnable(Counting countingObj) {
        this.countingObj = countingObj;
    }

    public void run() {
        for(int i = 0;i<10;i++) {
            countingObj.counter();
        }
    }
}

public class MulTi {
    public static void main(String[] args) throws Exception {
        // 创建唯一的Counting实例,让两个线程共享
        Counting sharedCounting = new Counting();
        
        // 给两个Runnable传入同一个实例
        CounterRunnable r1 = new CounterRunnable(sharedCounting);
        CounterRunnable r2 = new CounterRunnable(sharedCounting);
        
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        
        // 打印共享实例的count值
        System.out.println(sharedCounting.count); // 现在会输出20
    }
}

方式二:用静态变量实现共享(不推荐)

如果一定要保留原来的类结构,可以把Counting的count改成静态变量,这样所有实例共享同一个count值:

class Counting{
    public static int count ; // 静态变量,所有实例共享
    public synchronized void counter(){
        count = count + 1;
    }
}

class mulA implements Runnable{
    public void run() {
        Counting obj = new Counting();
        for(int i = 0;i<10;i++) {
            obj.counter();
        }
    }
}

class mulB implements Runnable{
    public void run() {
        Counting obj1 = new Counting();
        for(int i = 0;i<10;i++) {
            obj1.counter();
        }
    }
}

public class MulTi {
    public static void main(String[] args) throws Exception {
        mulA obj2 = new mulA();
        mulB obj3 = new mulB();
        Thread t1 = new Thread(obj2);
        Thread t2 = new Thread(obj3);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        
        System.out.println(Counting.count); // 输出20
    }
}

不过这种方式不推荐,因为静态变量的线程安全管理更复杂,而且不符合面向对象的设计原则。

额外优化建议

其实count = count + 1这个操作,即使加了synchronized是没问题的,但如果用JUC包的原子类(比如AtomicInteger)可以更简洁地实现线程安全的累加,不需要手动加锁:

import java.util.concurrent.atomic.AtomicInteger;

class Counting{
    public AtomicInteger count = new AtomicInteger(0);
    public void counter(){
        count.incrementAndGet(); // 原子操作,天然线程安全
    }
}

这样的写法更优雅,也避免了手动锁可能带来的问题。

内容的提问来源于stack exchange,提问作者nihit kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:50:57