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

