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

实现Runnable与继承Thread的线程同步差异问题咨询

为什么继承Thread同步this无法得到确定结果?

这是个非常经典的线程同步误区,咱们一步步拆解问题根源:

核心原理:同步锁的本质

synchronized(this)的核心是锁对象,而不是代码块本身。只有当多个需要同步的线程,争抢的是同一个对象实例作为锁时,才能实现串行执行,避免线程安全问题。

案例1(Runnable实现)的正确原因

在案例1中:

  • 你创建了一个One实例one,然后把它传给了两个Thread对象t1和t2
  • 两个线程的run方法里,this指向的都是同一个one对象
  • 当t1进入synchronized块时,会持有one的锁,t2必须等t1执行完释放锁后才能进入,所以两次10000次的累加是严格串行的,最终结果必然是20000。

案例2(Thread继承)的问题所在

在案例2中:

  • 你创建了两个独立的One实例o1和o2,虽然它们共享同一个counter对象,但run方法里的 synchronized(this)锁的是各自的实例:o1的this是o1,o2的this是o2
  • 这相当于两个线程各拿各的锁,互相不干扰,会同时执行counter.doCount()。而count++是非原子操作(拆成「读取count值→加1→写回count」三步),多个线程同时操作时会出现数据覆盖,所以结果是随机的。

解决方案

只要让两个线程争抢同一个锁对象就能解决问题,这里有几种常见方案:

方案1:锁共享的counter对象

修改案例2的run方法,把锁对象换成共享的counter:

public void run(){ 
    synchronized (counter) { 
        for(int i=0;i<10000;i++){ 
            counter.doCount(); 
        } 
    } 
}

方案2:给Counter的doCount方法加同步

直接在doCount方法上添加synchronized,这样每次调用该方法都会持有Counter实例的锁:

class Counter{ 
    int count; 
    public synchronized void doCount(){ 
        count=count+1; 
    } 
    public int getCount(){ 
        return count; 
    } 
}

方案3:使用原子类(无需手动同步)

用AtomicInteger代替普通int,它的incrementAndGet()方法是原子操作,天生线程安全:

import java.util.concurrent.atomic.AtomicInteger;

class Counter{ 
    AtomicInteger count = new AtomicInteger(0); 
    public void doCount(){ 
        count.incrementAndGet(); 
    } 
    public int getCount(){ 
        return count.get(); 
    } 
}

总结

线程同步的关键不是「是否共享资源」,而是「所有需要同步的线程是否使用同一把锁」。只要锁对象是同一个,不管是实现Runnable还是继承Thread,都能实现正确的同步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:05:25