Java多线程synchronized与Lock加锁不生效,静态变量自增结果随机是什么原因?
核心问题本质
所有锁机制生效的前提是多个线程竞争同一把共享锁,你的前两种写法都是每个线程持有独立的锁,完全没有互斥效果,自然无法保证静态共享变量count自增操作的原子性。
写法1(Lock版本)错误原因
你在test()方法内部每次执行时都会新建一个独立的ReentrantLock实例:
public void test() { Lock lock = new ReentrantLock(); // 每次调用test都会创建新锁 // ... }
1000个任务对应1000个完全独立的Lock实例,线程之间不会互相抢占锁,并发修改count时会出现值覆盖,最终结果小于等于1000。
正确的Lock写法需要将锁声明为类级静态共享变量,所有线程竞争同一把锁:
public class aaa implements Runnable { static int count = 0; // 全局唯一的共享锁 static Lock lock = new ReentrantLock(); // ... public void test() { try { lock.lock(); count++; System.out.println(count); } finally { lock.unlock(); } } }
写法2(synchronized实例方法版本)错误原因
synchronized修饰实例方法时,锁对象是当前实例this。你提交任务时每次都新建aaa实例:
for (int i = 0; i < 1000; i++) { aaa thread = new aaa(); // 每次新建实例 executor.execute(thread); }
1000个任务对应1000个不同的aaa实例,每个线程锁的是自己的实例对象,互相之间没有互斥关系,还是会出现并发修改冲突。
锁aaa.class写法生效的原理
aaa.class是类对象,JVM中每个类只会有唯一的一个类对象,属于全局共享的锁对象,所有线程都要竞争这同一把锁,同一时间只会有一个线程执行同步块内的代码,既保证了count++的原子性,也保证了打印顺序的连续性,最终结果一定是1000。
总结
count是static修饰的类级共享变量,要保护它的并发安全,锁也必须是类级别的全局共享锁,不能使用每个实例独有的锁。
内容的提问来源于stack exchange,提问作者e e
相关产品推荐
相关产品推荐

