Java线程安全问题浅析
2021/10/29 20:12:41
本文主要是介绍Java线程安全问题浅析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1.线程不安全现象
创建测试类和库存类如下,在测试类中启动两个线程,分别增加10000个库存和减少10000个库存。
public class Test { public static void main(String[] args) { Inventory inventory = new Inventory(0); Thread t1 = new Thread(() -> { for (int i = 0; i < 10000; i++) { inventory.increment(); } }, "t1"); Thread t2 = new Thread(() -> { for (int i = 0; i < 10000; i++) { inventory.decrement(); } }, "t2"); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } finally { System.out.println("test result vaule:" + inventory.get()); } } } /** * thread unsafe * */ class Inventory { private int count; public Inventory(int count) { this.count = count; } public void increment() { count++; } public void decrement() { count--; } public int get() { return count; } }
程序运行预期结果应该是0,但实际结果可能出现0,正数,负数。
2.原因
使用javap查看Inventory.class对应的字节码,可以看到count++,由多个指令构成,如下:
getfield //获得成员变量
iconst_1 //准备常量1
iadd //执行加法操作
putfield //将计算后的结果写回成员变量
count--类似,同样包含取值,准备常量1,执行减法,回写值这几个指令。
当多线程读写count值时候,可能情况如下(引用第三方图片,读者将图中i当作count即可):
或者
这也就解释了上述代码执行结果为何会出现正数,负数。
3.解决方案
加锁,将increment,decrement操作上锁,当前线程未执行完释放锁,其他线程无法执行。
/** * thread safe * */ class Inventory1 { private int count; public Inventory1(int count) { this.count = count; } public synchronized void increment() { count++; } public synchronized void decrement() { count--; } public int get() { return count; } }
CAS,每次写入之前检查count值是否被其他线程更新,如果已经更新,重新计算写入新值;如果未被更新,直接写入计算结果。
/** * thread safe * */ class Inventory2 { private AtomicInteger count; public Inventory2(int count) { this.count = new AtomicInteger(count); } public void increment() { // CAS while (true) { int prev = count.get(); int next = prev + 1; if (count.compareAndSet(prev, next)) { break; } } // 可简写如下 // count.getAndIncrement(); } public void decrement() { // CAS while (true) { int prev = count.get(); int next = prev - 1; if (count.compareAndSet(prev, next)) { break; } } // 可简写如下 // count.getAndDecrement(); } public int get() { return count.get(); } }
这篇关于Java线程安全问题浅析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-06小米11i印度快充版ROM合集:极致体验,超越期待
- 2024-10-06【ROM下载】小米11i 5G 印度版系统, 疾速跃迁,定义新速度
- 2024-10-06【ROM下载】小米 11 青春活力版,青春无极限,活力全开
- 2024-10-05小米13T Pro系统合集:性能与摄影的极致融合,值得你升级的系统ROM
- 2024-10-01基于Python+Vue开发的医院门诊预约挂号系统
- 2024-10-01基于Python+Vue开发的旅游景区管理系统
- 2024-10-01RestfulAPI入门指南:打造简单易懂的API接口
- 2024-10-01初学者指南:了解和使用Server Action
- 2024-10-01Server Component入门指南:搭建与配置详解
- 2024-10-01React 中使用 useRequest 实现数据请求