挥发性与primefaces性
我读到下面的地方。
Java volatile关键字并不意味着primefaces化,它的常见误解是,在声明volatile之后,
++
操作将是primefaces操作,为了使操作primefaces化,还需要使用Java中的synchronized
方法或块来确保独占访问。
那么如果两个线程同时攻击一个volatile
variables,会发生什么呢?
这是否意味着谁locking了它,这将首先确定它的价值。 而如果在此期间,其他线程出现并读取旧值,而第一个线程正在改变它的值,那么不新的线程将读取其旧值?
Atomic和volatile关键字有什么区别?
volatile
关键字的作用大约是对该variables的每个单独的读或写操作是primefaces的。
然而值得注意的是,需要多个读/写的操作 – 例如相当于i = i + 1
,它执行一次读取和一次写入 – 不是primefaces的,因为另一个线程可能会写入i
在读和写之间。
像AtomicInteger
和AtomicReference
这样的Atomic
类提供了更多的primefaces操作,具体包括AtomicInteger
增量。
易失性和primefaces是两个不同的概念。 易失性确保在不同的线程中某个预期的(记忆)状态是真实的,而Atomics确保对variables的操作是以primefaces方式执行的。
以Java中的两个线程为例:
线程A:
value = 1; done = true;
线程B:
if (done) System.out.println(value);
从value = 0
开始, done = false
,线程规则告诉我们,线程B是否会打印值是未定义的。 此外, 价值在这一点上是不确定的! 为了解释这一点,您需要了解一些关于Java内存pipe理(可能很复杂)的问题,简而言之:线程可能会创buildvariables的本地副本,并且JVM可以重新对代码进行重新sorting来优化它,因此不能保证上面的代码按照正确的顺序运行。 将设置为true, 然后将值设置为1可能是JIT优化的可能结果。
volatile
只能确保在访问这样一个variables的时刻,新的值将被所有其他线程直接看到, 并且执行顺序可以确保代码处于你期望的状态。 因此,在上面的代码中,将volatile定义为volatile将确保每当线程B检查variables时,该variables为false或true,如果为true,则value
也被设置为1。
作为volatile的一个副作用,这个variables的值是以primefaces方式在线程范围内设置的(执行速度很小)。 然而,这只对使用长(64位)variables(或类似)的32位系统很重要,在大多数情况下,设置/读取variables是primefaces无论如何。 但是在primefaces访问和primefaces操作之间有一个重要的区别。 挥发性只能确保访问是primefaces性的,而Atomics确保操作是primefaces性的。
以下面的例子:
i = i + 1;
无论你如何定义我,一个不同的线程读取上面的行执行时的值可能会得到i或i + 1,因为操作不是primefaces的。 如果另一个线程把我设置为一个不同的值,在最坏的情况下,我可以回到之前的线程A,因为它只是基于旧值计算i + 1,然后设置我再次以旧值+ 1解释:
Assume i = 0 Thread A reads i, calculates i+1, which is 1 Thread B sets i to 1000 and returns Thread A now sets i to the result of the operation, which is i = 1
像AtomicInteger这样的Atomics确保这样的操作是自发的。 所以上述问题不会发生,一旦两个线程都完成,我将是1000或1001。
multithreading环境中有两个重要的概念。
- primefaces
- 能见度
Volatile
消除了可见性问题,但不涉及primefaces性。 Volatile
将阻止编译器对涉及写入和随后读取易失性variables的指令进行重新sorting。 例如k++
这里k++
不是一个机器指令,而是三个机器指令。
- 复制值注册
- 增加它
- 把它放回去
所以,即使将variables声明为volatile
它也不会使此操作成为primefaces操作,这意味着另一个线程可以看到中间结果,这个结果对于另一个线程来说是一个陈旧的或不想要的值。
但是AtomicInteger
, AtomicReference
是基于Compare和swap指令的 。 CAS有三个操作数:操作的存储位置V
,预期的旧值A
和新的值B
CAS
primefaces地将V
更新为新的值B
,但仅当V
中的值与预期的旧值A
匹配时; 否则它什么都不做。 无论哪种情况,都会返回V
当前值。 这由JVM在AtomicInteger
, AtomicReference
使用,并且它们以compareAndSet()
调用函数。 如果底层处理器不支持这个function,那么JVM通过旋转锁来实现它。
正如所示的那样, volatile
只与可见性有关。
在并发环境中考虑这个片段:
boolean isStopped = false; : : while (!isStopped) { // do some kind of work }
这里的想法是,某个线程可以将isStopped
的值从false更改为true,以便向后续的循环指示是停止循环的时间。
直观地说,没有问题。 逻辑上,如果另一个线程使isStopped
等于true,则循环必须终止。 事实上,即使另一个线程使isStopped
等于true,循环也可能永远不会终止。
其原因并不直观,但考虑到现代处理器具有多个内核,并且每个内核具有多个寄存器和多个其他处理器无法访问的caching内存。 换句话说,高速caching在一个处理器的本地内存中的值对于在不同处理器上执行的线程是不可访问的 。 这就是并发的核心问题之一:可见性。
Java内存模型不保证何时对线程中的variables所做的更改可能对其他线程可见。 为了保证更新一旦生成就可以访问,您必须同步。
volatile
关键字是一种弱的同步forms。 虽然它对于互斥或primefaces性没有任何作用,但它确实提供了一个保证,即在一个线程中对一个variables所做的更改一旦被创build,就会对其他线程变得可见。 由于个人读取和写入不是8字节的variables在Java中是primefaces性的,因此声明variablesvolatile
提供了一种简单的机制,在没有其他primefaces性或互斥排除要求的情况下提供可见性。
那么如果两个线程同时攻击一个volatilevariables,会发生什么呢?
通常每个人都可以递增价值。 但是有时候,两者都会同时更新值,而不是递增2,而是增加1和1。
这是否意味着谁locking了它,这将首先确定它的价值。
没有锁。 这是synchronized
的。
而如果在其间,其他线程在第一个线程正在改变它的值的时候出现并读取旧值,那么新线程是否会读取它的旧值?
是,
Atomic和volatile关键字有什么区别?
AtomicXxxx封装了一个volatile,所以它们基本相同,不同之处在于它提供了更高级别的操作,比如用来实现增量的CompareAndSwap。
AtomicXxxx也支持lazySet。 这就像一个易失性集合,但不会阻塞等待写入完成的stream水线。 这可能意味着,如果你读到一个价值,你只是写下你可能会看到旧的价值,但是你不应该这样做。 不同的是,设置一个volatile需要大约5 ns,lazySet大约需要0.5 ns。
使用volatile
关键字:
- 使非primefaces64位操作primefaces:
long
和double
。 (所有其他原始访问已经保证是primefaces的!) - 保证variables的更新保证被其他线程看到+可见性效果:在写入一个volatilevariables之后,在写入该variables之前可见的所有variables在读取同一个volatilevariables(在订购之前发生)之后对另一个线程可见。
根据java文档 , java.util.concurrent.atomic.*
类是:
一个支持单variables无锁线程安全编程的小型工具包。 本质上,这个包中的类将volatilevariables值,字段和数组元素的概念扩展为那些也提供了表单的primefaces条件更新操作的variables:
boolean compareAndSet(expectedValue, updateValue);
primefaces类是围绕primefacescompareAndSet(...)
函数构build的,映射到primefacesCPU指令。 primefaces类引入了发生之前的sorting作为volatile
variables。 (有一个例外: weakCompareAndSet(...)
)。
从Java文档:
当一个线程看到由weakCompareAndSet引起的一个primefacesvariables的更新时,它不一定会看到在weakCompareAndSet之前发生的任何其他variables的更新。
对你的问题:
这是否意味着谁locking了它,这将首先确定它的价值。 而如果在其间,其他线程在第一个线程正在改变它的值的时候出现并读取旧值,那么新线程是否会读取它的旧值?
你不locking任何东西,你所描述的是一个典型的竞争条件,如果线程访问共享数据而没有正确的同步,最终会发生。 正如已经提到的那样,在这种情况下声明variablesvolatile
将只确保其他线程将看到variables的变化(该值不会被caching在只有一个线程看到的某个caching的寄存器中)。
AtomicInteger
和volatile int
什么区别?
AtomicInteger
通过适当的同步(例如incrementAndGet()
, getAndAdd(...)
,…)提供对int
primefaces操作, volatile int
将确保int
对其他线程的可见性。