volatile、synchronize的特点和区别

volatile和synchronize的区别

  • 线程安全
  • volatile关键字的使用
  • volatile为什么不能保证 i++的线程安全?因为 i++ 不是原子操作
  • volatile和synchronize的特点
  • volatile和synchronized的区别

各位,先大概了解什么是线程安全吧?

线程安全

  • 线程安全指的是内存的安全,在每个进程的内存空间中都会有一块特殊的公共区域,通常称为堆(内存)。进程内的所有线程都可以访问到该区域,这就是造成问题的潜在原因。
  • 所以线程安全指的是,在堆内存中的数据由于可以被任何线程访问到,在没有限制的情况下存在被意外修改的风险。即堆内存空间在没有保护机制的情况下,对多线程来说是不安全的地方,因为你放进去的数据,可能被别的线程“破坏”。

volatile关键字的使用

  1. 线程的可见性:当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。加了volatile关键字修饰的变量,只要有一个线程将主内存中的变量值做了修改,其他线程都将马上收到通知,立即获得最新值。
  2. 有序性:是通过禁止指令重排序来实现的有序性。
  3. 不保证原子性:原子性指的是:当某个线程正在执行某件事情的过程中,是不允许被外来线程打断的。也就是说,原子性的特点是要么不执行,一旦执行就必须全部执行完毕。而volatile是不能保证原子性的,即执行过程中是可以被其他线程打断甚至是加塞的。
  4. 这就引出另外一个问题了volatile为什么不能保证 i++的线程安全

volatile为什么不能保证 i++的线程安全?因为 i++ 不是原子操作

i++ 为什么不是原子操作?i++ 是分为三步 有序 的执行而不是一个整体 :

  • 从工作内存读取i值
  • 进行计算
  • 将值赋给i (注:后续由jvm将工作内存刷回主内存不一定立即执行 并且其它线程不一定立即去load)

以上每个步骤结束都有可能发生调度。用volatile 修饰 虽然保证了 从工作内存写入主内存后其它线程工作内存的可见性,但无法影响其它线程执行的i++步骤 。从而导致即使加了volatile 也不是线程安全的, 推荐i++ 操作 不用volatile直接加 synchronized锁 或者 更推荐使用 AtomicInteger CAS类 性能更好
volatile、synchronize的特点和区别_第1张图片
这一块可以先去看看Java的内存模型

volatile和synchronize的特点

在讲解两者特点之前,先理解线程安全的两个方面:执行控制和内存可见。

  • 执行控制:目的是控制代码执行(顺序)及是否可以并发执行。

  • 内存可见:控制的是线程执行结果在内存中对其它线程的可见性。根据Java内存模型的实现,线程在具体执行时,会先拷贝主存数据到线程本地空间中,操作完成后再把结果从线程本地刷到主存。

  • synchronized关键字解决的是执行控制的问题,它会阻止其它线程获取当前对象的锁,这样就使得当前对象中被synchronized关键字保护的代码块无法被其它线程访问,也就无法并发执行。

  • volatile关键字解决的是内存可见性的问题,会使得所有对volatile变量的读写都会直接刷到主存,这样就能满足一些对变量可见性有要求而对读取顺序没有要求的需求。

volatile和synchronized的区别

  1. volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;
    synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  2. volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
  3. volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
  4. volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。

你可能感兴趣的:(面试题,Java,jvm,java)