i++原子性, synchronized加锁

目的

  • 验证 i++ 的非原子性

环境配置

  • idea中下载插件jclasslib 用于查看字节码

测试 i++ 是否存在并发安全

代码Demo

  • 开十个线程,每个线程执行 i++ 1万次,看最后 结果 是否是 10万
public class AtomicTest {

    private static int i = 0;

    public static void main(String[] args) throws InterruptedException {
        // 运行 10 个线程
        for (int j = 0; j < 10; j++) {
            Thread thread = new Thread(() -> {
                // 每个线程 加 1万次
                for (int k = 0; k < 10000; k++) {
                    i++;
                }
            });
            thread.start();
        }

        // 等2秒,所有线程跑完,查看最终结果
        Thread.sleep(2000);
        System.out.println("i = " + i);
    }
}

运行结果

  • 结果随机,不是 10万

原因分析

  1. 查看字节码
    在这里插入图片描述
    在这里插入图片描述

  2. 通过 jclasslib 查看字节码可知,在 jvm 层面,i++ 可以分解为多个子操作,大概包括:取值,加一,设置值。由于这几个操作整体的非原子性,导致可能多个线程同时 加一,最后互相覆盖值,使得最终的结果不够 10万。

解法一:使用 synchronized 加锁

  1. i++操作用 synchronized加锁,修改后的代码
public class AtomicTest {

    private static int i = 0;

    public static void main(String[] args) throws InterruptedException {
        // 运行 10 个线程
        for (int j = 0; j < 10; j++) {
            Thread thread = new Thread(() -> {
                // 每个线程 加 1万次
                for (int k = 0; k < 10000; k++) {
                    synchronized (AtomicTest.class) {
                        i++;
                    }
                }
            });
            thread.start();
        }

        // 等2秒,所有线程跑完,查看最终结果
        Thread.sleep(2000);
        System.out.println("i = " + i);
    }
}
  1. 查看字节码
    在这里插入图片描述
  2. 看到了熟悉了 monitorentermonitorexitsynchronized 是在 jvm 层面的加锁,释放锁
  • 13
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值