synchronized、volatile以及CAS的区别

在讲解synchronized、volatile、CAS的区别之前,需要弄明白什么共享资源、什么是线程安全、线程间的可见性问题以及Java操作的原子性。弄明白这些问题可以加深你对synchronized、volatile、CAS的理解。下面我会先对这些问题进行简单的说明,

 

什么是资源共享?

同一个资源被多个线程所持有 或者说多个线程可以访问该资源,这样的资源称之为共享资源。

 

什么线程安全?

就是指多个线程同时读写同一个资源,并没有使用任何的同步措施,导致出现脏数据或者不可预见的结果。

注:如果多个线程只是访问共享资源,而不去修改的话,是不存在线程安全问题的。只有当线程修改共享资源的时候,才会出现线程安全问题。

 

线程间的可见性问题

java内存模型规定,所有的变量都存放在主内存中,当线程使用变量的时候,会把主内存中的变量赋值到自己的工作内存中,线程读写变量时,操作的是线程自己内存中变量。

进一步解读:

1、变量(也就是共享资源)存储在主内存中

2、线程使用变量的时候,会在自己的工作内存保存该变量的副本。

3、线程在工作内存中修改副本,并把修改后的变量副本同步到主内存中

4、主内存中的变量已经发生了改变,但不会将修改后的变量同步给其他线程,其他线程的工作空间中的副本变量的值还是修改前的值,也就造成了线程间资源的同步问题

这也就是线程间的不可见性

 

java操作的原子性

所谓的原子性操作,就是指执行一系列操作的时候,这些操作要么全部执行,要么全部不执行,不存在指执行一部分的情况。

在一些面试中,++i是原子性操作吗?通过一个示例简单的计数器进行说明,代码如下:

public class ThreadNotSafeCount {
    private int count;

    public int getCount() {
        return count;
    }

    public synchronized void  inc(){
        ++count;
    }
}

使用过javap  -c查看汇编代码,如下所示:

其中,简单的++count由2、5、6、7四步组成,也就是红框中所标识的汇编代码,其中第2步是获取当前count的值并放入栈顶,第5步是把常量1放入栈顶,第6步是把放入栈顶的两个值相加并把结果放入栈顶,第7步是把栈顶的结果赋值给count。由此可以发现++count,包含了count的读--改--写过程,所以++count不是一个原子性操作。

 

线程间不可见性的解决方案

synchronized锁机制解决线程间的可见性问题

线程synchronized加锁时,其他线程会进入阻塞,而该线程会清空锁块内线程工作内存中的变量,在使用这些变量的时候,会从主内存中加载。synchronized在释放锁时,会将线程工作空间中的变量同步到主内存中。这样也就解决了线程间的可见性问题。

 

volatile关键字解决线程间的可见性问题

当变量使用volatile关键字修饰变量,线程在使用该变量的时候会去主内存中读取,修改后,会把值同步给主内存。这跟synchronized有点类似。

 

synchronized锁机制和volatile关键字解决线程间的可见性问题的区别

使用synchronized锁机制,当线程获得锁之后,其他线程的调用会被阻塞,同时也会增加线程上下文切换和线程重新调度的开销。

使用volatile关键字,是非阻塞式解决方案,不会增加线程的上下文切换以及线程重新调度的开销。

 

如何确保java的原子性操作?

sychronized锁机制,当线程进入synchronized代码块前,获得锁,其他线程就会被阻塞挂起。当该线程正常退出或者抛出异常或者调用wait()系列方法释放锁时,其他线程才有机会获得锁,执行该代码块。简而言之,sychronized锁机制通过阻塞来确保java操作的原子性。

volatile关键字并不会保证操作的原子性。

 

小小总结

synchronized能解决线程之间的可见性问题和确保java操作的原子性,但是会做成线程阻塞,增加线程上下文切换和线程重新调到的开销问题、

volatile能通过非阻塞式的方式解决了线程间的可见性问题,但不能保证java操作的原子性。也不会增加线程切换和线程重新调度的开销问题。

 

什么是CAS?

CAS就是Compare And Swap,是JDK提供给的非阻塞性原子性操作。它通过硬件保证了比较--更新的原子性操作。JDK中的Unsafe提供了一些列的CAS方法,Unsafe类中的方法都是native方法,它们通过使用JNI的方式访问本地的C++实现库。


下面就compareAndSwapLong()方法进行简单介绍

public final native boolean compareAndSwapLong(Object Obj, long valueOffset, long expect, long update);

其中compareAndSwap的意思就是比较交换,CAS有四个操作数,分别为:对象内位置,对象中的变量的偏移量,变量的预期值和新的值。其操作含义是,如果obj中的内存偏移量为valueOffset,则使用新的值update替换旧的值expect。这是处理器提供的一个原子性指令

 

参考:《java并发编程之美》

 

 

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值