java 中的synchronized及其锁升级的理解

14 篇文章 0 订阅

synchronized的作用

示例

public static void main(String[] args) throws Exception {
    for (int i = 0; i < 10; i++) {
        new Thread(()->{
            incrment();
        }).start();
    }
    Thread.sleep(3000);
    System.out.println(num);
}

private static int num = 0;

public static void incrment(){
    for (int i = 0; i < 1000; i++) {
        num++;
    }
}

运行结果

9448

Process finished with exit code 0

incrment()是对变量num进行1000词的++操作,示例中使用10个线程去执行incrment()方法,期望的结果是num值为10000,但运行出来的结果却小于10000。这是为什么呢?

当对num进行++操作,多个线程同时访问时,第一个线程将num读出来,假设读到的是0,然后把它+1,但在这个还没有写回去的时候,第二个线程来了读到它还是0,也对其+1,之后写回去,发现两个线程都是读到的0,写回去的是1,本来应该加两次变成2,结果却是1,这就出现了少加的现象

加锁可以有效的解决这种现象
加锁后的代码

public static void main(String[] args) throws Exception {
    for (int i = 0; i < 10; i++) {
        new Thread(()->{
            incrment();
        }).start();
    }
    Thread.sleep(3000);
    System.out.println(num);
}
private static int num = 0;
public synchronized static void incrment(){
    for (int i = 0; i < 1000; i++) {
        num++;
    }
}

运行结果

10000

Process finished with exit code 0

使用synchronized加锁后得到所期望的结果,当第一线程执行incrment()结束之前不允许其他线程也执行此方法

synchronized锁的是什么

当锁的方法为普通方法时,锁的是当前对象,也就this
当锁的方法为静态方法时,由于静态方法没有this,所有锁的是当前类的class

注:synchronized是可重入的,如果代码出现了异常,锁会被释放

synchronized的底层实现

JDK早期的时候,synchronized是重量级的,需要找操作系统去申请锁,这是synchronized性能很低;后来synchronized改进之后有了锁升级的概念,当使用synchronized时在对象头(markword)记录这个线程,只有一个线程访问时内部只记录了这个线程的ID并没有加锁,如果有线程争用时才会升级为轻量级锁,线程数多了之后会升级到重量级锁

锁的升级

不加锁:顾名思义,不使用synchronized加锁
偏向锁:在线程无竞争时消除同步操作,如果该锁一直没有被其他线程获取,那么这个线程不进行同步操作;一旦出现另一个线程去尝试获取这把锁,偏向锁会立刻转换为轻量级锁
轻量级锁:JVM使用CAS的方式更改markword中的锁状态来实现的,它在没有多线程竞争的前提下,减少系统互斥量操作产生的性能消耗
重量级锁:JVM调用了操作系统提供的同步机制,也就是硬件层面的一条指令。lock cmpxchg xxx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值