如何正确使用Java的synchronized关键字?线程累加计数异常排查
Java synchronized 同步失效问题分析与修复
你的代码中synchronized修饰实例方法run()的方式错误,导致线程未正确同步。
问题根源
synchronized修饰实例方法时,锁定的是当前实例对象。你创建了thr和thr2两个不同的Threadproblem实例,两个线程各自持有不同的锁,彼此的操作不会互相阻塞,因此静态变量counter的累加操作会出现线程安全问题,最终结果小于预期的200000。
修复方案
方案1:使用静态同步方法
将累加逻辑抽成静态同步方法,此时锁定的是Threadproblem类对象,所有线程共享同一把锁:
public class Threadproblem extends Thread { static long counter; synchronized public static void increment() { counter++; } @Override public void run() { for (int i = 0; i < 100000; i++) { increment(); } } public static void main(String[] args) { Threadproblem thr = new Threadproblem(); Threadproblem thr2 = new Threadproblem(); thr.start(); thr2.start(); try { thr.join(); thr2.join(); } catch (InterruptedException e) { System.out.println(e); } System.out.println("Counts:" + counter); } }
方案2:锁定类对象的同步块
在run()方法中,直接对Threadproblem类对象加锁,确保所有线程共用同一锁:
public class Threadproblem extends Thread { static long counter; @Override public void run() { synchronized (Threadproblem.class) { for (int i = 0; i < 100000; i++) { counter++; } } } public static void main(String[] args) { Threadproblem thr = new Threadproblem(); Threadproblem thr2 = new Threadproblem(); thr.start(); thr2.start(); try { thr.join(); thr2.join(); } catch (InterruptedException e) { System.out.println(e); } System.out.println("Counts:" + counter); } }
方案3:共用同一个Runnable实例
让多个线程共享同一个任务实例,此时synchronized修饰的实例方法会锁定这个共享的任务对象,实现同步:
public class Threadproblem implements Runnable { private long counter; @Override public synchronized void run() { for (int i = 0; i < 100000; i++) { counter++; } } public static void main(String[] args) throws InterruptedException { Threadproblem task = new Threadproblem(); Thread thr = new Thread(task); Thread thr2 = new Thread(task); thr.start(); thr2.start(); thr.join(); thr2.join(); System.out.println("Counts:" + task.counter); } }
补充说明
counter++是非原子操作,包含读取当前值、加1、写回新值三个步骤,即使没有循环,单个counter++也需要同步机制保证原子性,上述方案均已解决该问题。
内容的提问来源于stack exchange,提问作者SBAT
相关产品推荐
相关产品推荐

