首页 > 试题广场 >

volatile关键字的说法错误的是

[单选题]
volatile关键字的说法错误的是
  • 能保证线程安全
  • volatile关键字用在多线程同步中,可保证读取的可见性
  • JVM保证从主内存加载到线程工作内存的值是最新的
  • volatile能禁止进行指令重排序
推荐
A
出于运行速率的考虑,java编译器会把经常经常访问的变量放到缓存(严格讲应该是工作内存)中,读取变量则从缓存中读。但是在多线程编程中,内存中的值和缓存中的值可能会出现不一致。volatile用于限定变量只能从内存中读取,保证对所有线程而言,值都是一致的。但是volatile不能保证原子性,也就不能保证线程安全。
编辑于 2015-12-30 18:42:01 回复(15)
A
发表于 2015-04-22 14:49:36 回复(1)

1.java的内存模型

java 内存模型规定了所有的变量都存储在主内存中,但是每个线程会有自己的工作内存,线程的工作内存保存了该线程中使用了的变量(从主内存中拷贝的),线程对变量的操作都必须在工作内存中进行,不同线程之间无法直接访问对方工作内存中的变量,线程间变量值从传递都要经过主内存完成

图片说明


2.什么是原子性

一个操作是不可中断的,要么全部执行成功要么全部执行失败,比如银行转账


3.什么是可见性

当多个线程访问同一变量时,一个线程修改了这个变量的值,其他线程就能够立即看到修改的值


4.什么是有序性

程序执行的顺序按照代码的先后顺序执行

int a = 0; //1
int b = 2; //2

像这2句代码1会比2先执行,但是jvm在正真执行时不一定是1在2之前,这里涉及一个概念叫做指令重排,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。比如上面的代码语句1和语句2谁先执行对最终的程序结果并没有影响,那么就有可能在执行过程中,语句2先执行而语句1后执行。
在指令重排时会考虑指令之间的数据依赖性,比如2依赖了1的数值,那么处理器会保证1在2之前执行。
但是在多线程的情况下,指令重排就会有影响了。


5.volatile到底做了什么

  • 禁止了指令重排
  • 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量值,这个新值对其他线程是立即可见的
  • 不保证原子性(线程不安全)
编辑于 2018-08-27 14:25:00 回复(16)

Java中的volatile关键字的功能

volatile是java中的一个类型修饰符。它是被设计用来修饰被不同线程访问和修改的变量。如果不加入volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器 失去大量优化的机会。

1,可见性

    可见性指的是在一个线程中对该变量的修改会马上由工作内存(Work Memory)写回主内存(Main Memory),所以会马上反应在其它线程的读取操作中。顺便一提,工作内存和主内存可以近似理解为实际电脑中的高速缓存和主存,工作内存是线程独享的,主存是线程共享的。

2,禁止指令重排序优化

    禁止指令重排序优化。大家知道我们写的代码(尤其是多线程代码),由于编译器优化,在实际执行的时候可能与我们编写的顺序不同。编译器只保证程序执行结果与源代码相同,却不保证实际指令的顺序与源代码相同。这在单线程看起来没什么问题,然而一旦引入多线程,这种乱序就可能导致严重问题。volatile关键字就可以从语义上解决这个问题。

    注意,禁止指令重排优化这条语义直到jdk1.5以后才能正确工作。此前的JDK中即使将变量声明为volatile也无法完全避免重排序所导致的问题。所以,在jdk1.5版本前,双重检查锁形式的单例模式是无法保证线程安全的。因此,下面的单例模式的代码,在JDK1.5之前是不能保证线程安全的。

发表于 2017-03-23 17:13:57 回复(4)
我们都知道jvm运行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了
发表于 2015-08-15 20:17:13 回复(1)
1.我们都知道jvm运行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。
2.出于运行速率的考虑,java编译器会把经常经常访问的变量放到缓存(严格讲应该是工作内存)中,读取变量则从缓存中读。但是在多线程编程中,内存中的值和缓存中的值可能会出现不一致。volatile用于限定变量只能从内存中读取,保证对所有线程而言,值都是一致的。但是volatile不能保证原子性,也就不能保证线程安全。
发表于 2015-11-04 16:58:20 回复(3)
1.volatile修饰的变量是读可见性的,什么意思呢,就是所有线程读取该变量的值都是正确的,变量写入这一动作,会被编译成机器指令,并且,是先写入到当前线程的工作内存而不是主内存(不懂的看看java 内存模型去),但是volatile修饰的变量的修改写入动作会被直接写入主内存,写入的同时会通过总线发出信号宣告其他线程的内存区该变量的值无效(即过时的),当其他线程去读该变量的值的时候,会发现工作内存的值过时了,就会到主内存去读该变量的值,所以是读可见性的。
2. 为什么不是线程安全的呢?这是因为原子性问题,什么是原子性?大家知道cpu工作是以时间片的方式分配cpu资源,当一个线程正在执行的时候,如果此时失去时间片,那么它所有的工作都要暂停,原子性就是:一个完整不再能分割的操作。即使是时间片结束,也要完成当前的原子操作,否则不允许切换。 Synchronized:保证可见性和原子性, 在Java内存模型中,synchronized规定,线程在加锁时 ,先清空工作内存→在主内存中拷贝最新变量的副本到工作内存→执行完代码→将更改后的共享变量的值刷新到主内存中→释放互斥锁 。参java并发编程艺术与博客http://blog.csdn.net/guyuealian/article/details/52525724
发表于 2017-02-23 22:27:22 回复(0)
volatile的两个特点:
1.保证读取的可见性
2.禁止指令重排
发表于 2015-09-24 22:03:50 回复(3)
volatile用于限定变量只能从内存中读取,保证对所有线程而言,值都是一致的。但是不能说volatile能保证线程安全。
发表于 2017-01-12 15:45:08 回复(0)
  • Volatile:与锁相比,Volatile 变量是一种非常简单但同时又非常脆弱的同步机制,它在某些情况下将提供优于锁的性能和伸缩性。如果严格遵循 volatile 的使用条件 —— 即变量真正独立于其他变量和自己以前的值 —— 在某些情况下可以使用 volatile 代替 synchronized 来简化代码。然而,使用 volatile 的代码往往比使用锁的代码更加容易出错。
  • 您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
    • (1)对变量的写操作不依赖于当前值。
    • (2)该变量没有包含在具有其他变量的不变式中。
  • 实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。
  • 第一个条件的限制使 volatile 变量不能用作线程安全计数器。虽然增量操作(x++)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而 volatile 不能提供必须的原子特性。实现正确的操作需要使 x 的值在操作期间保持不变,而 volatile 变量无法实现这点。
volatile只保证多线程操作的可见性,不保证原子性。只有synchronized才保证了原子性和可见性。
发表于 2018-08-16 15:28:31 回复(1)
发表于 2018-03-26 16:38:05 回复(0)
volatile只能保证可见性和有序性,而无法保证原子性。所以volatile不是线程安全的。
发表于 2018-02-26 10:24:57 回复(0)
java主要的同步机制是synchronized,其他的同步机制还有volatile、显示锁、原子变量。
其中volatile只能保证内存可见性 不能保证原子性 .所以该用synchronized还是得用。
发表于 2016-08-15 14:20:40 回复(0)
volatile的两个特点: 1.保证读取的可见性 2.禁止指令重排
发表于 2022-02-24 19:14:23 回复(0)
violate不能保证原子性,也就不能保证线程的安全
发表于 2018-10-27 23:35:48 回复(0)
volatile用于限定变量只能从内存中读取,保证对所有线程而言,值都是一致的。
volatile不能保证原子性,也就不能保证线程安全。
发表于 2018-08-03 16:09:52 回复(0)
更准确的说,volatile保证变量读取不从寄存器或者高速缓存中读取。这个关键字,在c中也有。连续两行使用同一个变量的代码,很可能因线程安全问题使用了旧的副本,volatile可以解决这个问题
发表于 2018-05-03 12:30:34 回复(0)
D也不对
volatile只保证他的上下代码不能重排序而已啊 

例如  代码块1
      带有volatile的代码
      代码块2

只保证代码块1和代码块2的代码不会互相重排序 却不能保证 代码块1,代码块2各自不能重排序

发表于 2017-10-24 12:32:08 回复(1)
jvm运行时,为了保证运行的效率,会把内存中的值load到工作内存中,修改值会在工作内存中修改,在多线程中,有可能内存中的值和工作内存中的值不一致,volatile关键字保证变量只能从内存中取值,对所有线程而言,值都是一致的,但volatile不能保证原子性,所以也是线程不安全的。volatile可以禁止进行指令重排序,指令重排序是Java虚拟机运行时只保证指令运行结果于代码有一致性,不保证顺序也有一致性,使用volatile可以禁止指令重排序
编辑于 2017-09-22 14:41:04 回复(0)
volatile没有原子性,只有可读性和可见性!不保证线程安全
发表于 2016-06-28 20:28:30 回复(0)