|
Java支持多个线程同时访问一个对象或者对象的成员变量,由于每个线程可以拥有这个变量的拷贝(虽然对象以及成员变量分配的内存是在共享内存中的,但是每个执行的线程还是可以拥有一份拷贝,这样做的目的是加速程序的执行,这是现代多核处理器的一个显著特性),所以程序在执行过程中,一个线程看到的变量并不一定是最新的。
volatile volatile的应用 在多线程并发编程中 synchronized 和 volatile 都扮演着重要的角色,<mark>volatile 是一个轻量级的 synchronized ,它在多处理器开发中保证了共享变量的 可见性</mark>。可见性的意思是当一个线程修改一个共享变量的时候,另一个线程能读取到这个共享变量被修改后的值。如果 volatile 使用恰当的话,它比 synchronized 的使用和执行成本更低,因为 volatile 不会引起线程上下文的切换和调度
volatile的定义与实现原理 Java 编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致性地更新,线程应该确保通过排他锁来单独获取这个变量。Java 提供的 volatile 在某些情况下比锁要方便。如果一个字段被声明为 volatile,那么Java模型确保所有的线程看到这个变量的值是一致的
作用:
volatile关键字用作成员变量的修饰符,以强制单个线程每次从共享内存中重新读取变量的值
访问。 此外,各个线程被迫将更改写回到共享记忆一旦发生。 这样,两个不同的线程总是看到相同的在任何特定时间成员变量的值
volatile的两条实现原则- Lock 前缀指令会引起处理器缓存回写到内存
- 一个处理器的缓存回写到内存会导致其他的处理器的缓存无效
synchronized synchronized 关键字可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性
synchronized的实现原理与应用 在多线程并发编程中 synchronized 一直是元老级的角色,很多人都会直呼它为重量级锁。但是,随着 Java SE 1.6 对 synchronized 进行了各种优化之后,有些情况下synchronized 并没有那么重了
synchronized如何实现同步? synchronized 实现同步的基础:Java中的每一个对象都可以作为锁。具体的表现形式有以下三种:
- 对于普通同步方法,锁是当前实例对象
- 对于静态同步方法,锁是当前类的Class对象
- 对于同步方法块,锁是 synchronized 括号里配置的对象
当一个线程试图访问同步代码块时,必须先获取到锁,退出或抛出异常时必须释放锁
volatile 与 synchronized 的区别? | volatile | synchronized |
---|
修饰 | 只能用于修饰变量 | 可以用于修饰方法、代码块 | 线程阻塞 | 不会发生线程阻塞 | 会发生阻塞 | 原子性 | 不能保证变量的原子性 | 可以保证变量原子性 | 可见性 | 可以保证变量在线程之间访问资源的可见性 | 可以间接保证可见性,因为它会将私有内存中和公共内存中的数据做同步 | 同步性 | 能保证变量在私有内存和主内存间的同步 | synchronize是多线程之间访问资源的同步性 | - volatile 是线程同步的轻量级实现,所以 volatile 的性能要比 synchronize 好;随着jdk技术的发展,synchronize 在执行效率上会得到较大提升,所以 synchronize 在项目过程中还是较为常见的
- 对于 volatile 修饰的变量,可以解决变量读时可见性问题,无法保证原子性。对于多线程访问同一个实例变量还是需要加锁同步
在多线程定义中,volatile 关键字主要是在属性上使用的,表示此属性为直接数据操作,而不进行副本的拷贝处理。这样的话在一些书上就将其错误的理解为同步属性了。
package com .java .springtest .test ;
/**
* @author Woo_home
* @create by 2020/1/20
*/
public class ThreadDemo {
public static void main (String [ ] args ) throws Exception {
ThreadShop shopA = new ThreadShop ( ) ;
ThreadShop shopB = new ThreadShop ( ) ;
ThreadShop shopC = new ThreadShop ( ) ;
new Thread (shopA , "A 店铺" ) . start ( ) ;
new Thread (shopB , "B 店铺" ) . start ( ) ;
new Thread (shopC , "C 店铺" ) . start ( ) ;
}
}
class ThreadShop implements Runnable {
private volatile int product = 5 ; // 直接内存操作
@Override
public void run ( ) {
synchronized ( this ) {
while ( this .product > 0 ) {
try {
Thread . sleep ( 100 ) ;
} catch ( InterruptedException e ) {
e . printStackTrace ( ) ;
}
System .out . println (Thread . currentThread ( ) . getName ( ) + "商品处理,product = " + this .product -- ) ;
}
}
}
} |
![点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小](png/20200120120759949.png)
面试题: 请解释 volatile 与 synchronized 的区别?
- volatile 本质是在告诉 jvm 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized 则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
- volatile 仅能使用在变量级别;synchronized 则可以使用在变量、方法、和类级别
- volatile 仅能实现变量的修改可见性,不能保证原子性;而 synchronized 则可以保证变量的修改可见性和原子性
- volatile 不会造成线程的阻塞;synchronized 可能会造成线程的阻塞。
- volatile 标记的变量不会被编译器优化;synchronized 标记的变量可以被编译器优化
----------------------------
原文链接:https://blog.csdn.net/Woo_home/article/details/102651639
程序猿的技术大观园:www.javathinker.net
[这个贴子最后由 flybird 在 2020-02-24 12:50:09 重新编辑]
|
|