「java原子操作」java如何实现原子性
今天给各位分享java原子操作的知识,其中也会对java如何实现原子性进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
本文目录一览:
- 1、java原子操作会成为性能瓶颈吗?
- 2、原子操作的实现原理
- 3、请问java中的原子操作有哪些?
- 4、那些是原子操作?
- 5、Java多线程之Atomic:原子变量与原子类
- 6、什么是原子操作,java中的原子操作是什么
java原子操作会成为性能瓶颈吗?
会,原子性操作,意味着那段时间内 别人不能操作。操作就回滚,10000笔操作同时进来,每个5ms,那么意味着总共50000ms,才能跑完,或者等不了那么久,你就只能完成一部分,然后及时反馈给用户系统繁忙。
原子操作的实现原理
我们一起来聊一聊在Inter处理器和Java里是如何实现原子操作的。
32位IA-32处理器使用基于 对缓存加锁或总线加锁 的方式来实现多处理器之间的原子操作
首先处理器会自动保证基本的内存操作的原子性。 处理器保证从系统内存当中读取或者写入一个字节是原子的,意思是当一个处理器读取一个字节时,其他处理器不能访问这个字节的内存地址。奔腾6和最新的处理器能自动保证单处理器对同一个缓存行里进行16/32/64位的操作是原子的,但是复杂的内存操作处理器不能自动保证其原子性,比如跨总线宽度,跨多个缓存行,跨页表的访问。但是处理器提供总线锁定和缓存锁定两个机制来保证复杂内存操作的原子性。
第一个机制是通过总线锁保证原子性。 如果多个处理器同时对共享变量进行读改写(i++就是经典的读改写操作)操作,那么共享变量就会被多个处理器同时进行操作,这样读改写操作就不是原子的,操作完之后共享变量的值会和期望的不一致,举个例子:如果i=1,我们进行两次i++操作,我们期望的结果是3,但是有可能结果是2。如下图
处理器使用总线锁就是来解决这个问题的。 所谓总线锁就是使用处理器提供的一个LOCK#信号,当一个处理器在总线上输出此信号时,其他处理器的请求将被阻塞住,那么该处理器可以独占使用共享内存。
“缓存锁定”指内存区域如果被缓存在处理器的缓存行中,并且在Lock操作期间被锁定,那么当它执行锁操作回写到内存时,处理器不需要在总线上声言LOCK#信号,而是修改内部的内存地址,通过缓存一致性机制保证操作的原子性。
例外:当操作的数据不能被缓存在处理器内部,或操作的数据跨多个缓存行,处理器会调用总线锁定。
在java中可以通过锁和循环CAS的方式来实现原子操作。
CAS
ABA问题
循环时间长开销大
只能保证一个共享变量的原子操作
原子操作的实现原理
聊聊并发(五)原子操作的实现原理
请问java中的原子操作有哪些?
13是, 24不是, 但并不是楼上说的意思哦, 原子操作可以和多线程结合起来看。
首先楼主你要知道原子操作是什么,我的理解是符合多线程原子性操作的操作就叫原子操作。
原子是世界上的最小单位,具有不可分割性。比如 a=0;(a非long和double类型)这个操作
是不可分割的,那么我们说这个操作是原子操作。再比如:a++;这个操作实际是a = a + 1;
是可分割的,所以他不是一个原子操作。
例如 :你执行a = 1这个操作的时候, 是没有任何问题的, 但是当你执行a = b 的时候就有很大的问题了
假如这个时候别的线程改变了b的值, 那么a = b就会出现不同的结果, 因为b的值你并不能确定,
比如你第期望的是a = b,你认为b的值是3,所以a也是3,可是多线程情况下程序使b变成了
4,那么a也就变成了4,那这就不算一个原子操作。
那些是原子操作?
原子操作(atomic operation)意为”不可被中断的一个或一系列操作” 。处理器使用基于对缓存加锁或总线加锁的方式来实现多处理器之间的原子操作。在Java中可以通过锁和循环CAS的方式来实现原子操作。CAS操作——Compare Set,或是 Compare Swap,现在几乎所有的CPU指令都支持CAS的原子操作。
原子操作是指一个不受其他操作影响的操作任务单元。原子操作是在多线程环境下避免数据不一致必须的手段。int++并不是一个原子操作,所以当一个线程读取它的值并加1时,另外一个线程有可能会读到之前的值,这就会引发错误。
为了解决这个问题,必须保证增加操作是原子的,在JDK1.5之前我们可以使用同步技术来做到这一点。到JDK1.5,java.util.concurrent.atomic包提供了int和long类型的原子包装类,它们可以自动的保证对于他们的操作是原子的并且不需要使用同步。
Java多线程之Atomic:原子变量与原子类
一 何谓Atomic?
Atomic一词跟原子有点关系 后者曾被人认为是最小物质的单位 计算机中的Atomic是指不能分割成若干部分的意思 如果一段代码被认为是Atomic 则表示这段代码在执行过程中 是不能被中断的 通常来说 原子指令由硬件提供 供软件来实现原子方法(某个线程进入该方法后 就不会被中断 直到其执行完成)
在x 平台上 CPU提供了在指令执行期间对总线加锁的手段 CPU芯片上有一条引线#HLOCK pin 如果汇编语言的程序中在一条指令前面加上前缀 LOCK 经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低 持续到这条指令结束时放开 从而把总线锁住 这样同一总线上别的CPU就暂时不能通过总线访问内存了 保证了这条指令在多处理器环境中的原子性
二 ncurrent中的原子变量
无论是直接的还是间接的 几乎 ncurrent 包中的所有类都使用原子变量 而不使用同步 类似 ConcurrentLinkedQueue 的类也使用原子变量直接实现无等待算法 而类似 ConcurrentHashMap 的类使用 ReentrantLock 在需要时进行锁定 然后 ReentrantLock 使用原子变量来维护等待锁定的线程队列
如果没有 JDK 中的 JVM 改进 将无法构造这些类 这些改进暴露了(向类库 而不是用户类)接口来访问硬件级的同步原语 然后 ncurrent 中的原子变量类和其他类向用户类公开这些功能
ncurrent atomic的原子类
这个包里面提供了一组原子类 其基本的特性就是在多线程环境下 当有多个线程同时执行这些类的实例包含的方法时 具有排他性 即当某个线程进入方法 执行其中的指令时 不会被其他线程打断 而别的线程就像自旋锁一样 一直等到该方法执行完成 才由JVM从等待队列中选择一个另一个线程进入 这只是一种逻辑上的理解 实际上是借助硬件的相关指令来实现的 不会阻塞线程(或者说只是在硬件级别上阻塞了) 其中的类可以分成 组
AtomicBoolean AtomicInteger AtomicLong AtomicReference
AtomicIntegerArray AtomicLongArray
AtomicLongFieldUpdater AtomicIntegerFieldUpdater AtomicReferenceFieldUpdater
AtomicMarkableReference AtomicStampedReference AtomicReferenceArray
其中AtomicBoolean AtomicInteger AtomicLong AtomicReference是类似的
首先AtomicBoolean AtomicInteger AtomicLong AtomicReference内部api是类似的 举个AtomicReference的例子
使用AtomicReference创建线程安全的堆栈
Java代码
public class LinkedStackT {
private AtomicReferenceNodeT》 stacks = new AtomicReferenceNodeT》()
public T push(T e) {
NodeT oldNode newNode;
while (true) { //这里的处理非常的特别 也是必须如此的
oldNode = stacks get()
newNode = new NodeT(e oldNode)
if (pareAndSet(oldNode newNode)) {
return e;
}
}
}
public T pop() {
NodeT oldNode newNode;
while (true) {
oldNode = stacks get()
newNode = oldNode next;
if (pareAndSet(oldNode newNode)) {
return oldNode object;
}
}
}
private static final class NodeT {
private T object;
private NodeT next;
private Node(T object NodeT next) {
this object = object;
this next = next;
}
}
}
然后关注字段的原子更新
AtomicIntegerFieldUpdaterT/AtomicLongFieldUpdaterT/AtomicReferenceFieldUpdaterT V是基于反射的原子更新字段的值
相应的API也是非常简
单的 但是也是有一些约束的
( )字段必须是volatile类型的!volatile到底是个什么东西 请查看
( )字段的描述类型(修饰符public/protected/default/private)是与调用者与操作对象字段的关系一致 也就是说调用者能够直接操作对象字段 那么就可以反射进行原子操作 但是对于父类的字段 子类是不能直接操作的 尽管子类可以访问父类的字段
( )只能是实例变量 不能是类变量 也就是说不能加static关键字
( )只能是可修改变量 不能使final变量 因为final的语义就是不可修改 实际上final的语义和volatile是有冲突的 这两个关键字不能同时存在
( )对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段 不能修改其包装类型(Integer/Long) 如果要修改包装类型就需要使用AtomicReferenceFieldUpdater
在下面的例子中描述了操作的方法
[java]
import ncurrent atomic AtomicIntegerFieldUpdater;
public class AtomicIntegerFieldUpdaterDemo {
class DemoData{
public volatile int value = ;
volatile int value = ;
protected volatile int value = ;
private volatile int value = ;
}
AtomicIntegerFieldUpdaterDemoData getUpdater(String fieldName) {
return AtomicIntegerFieldUpdater newUpdater(DemoData class fieldName)
}
void doit() {
DemoData data = new DemoData()
System out println( == +getUpdater( value ) getAndSet(data ))
System out println( == +getUpdater( value ) incrementAndGet(data))
System out println( == +getUpdater( value ) decrementAndGet(data))
System out println( true == +getUpdater( value ) pareAndSet(data ))
}
public static void main(String[] args) {
AtomicIntegerFieldUpdaterDemo demo = new AtomicIntegerFieldUpdaterDemo()
demo doit()
}
}
在上面的例子中DemoData的字段value /value 对于AtomicIntegerFieldUpdaterDemo类是不可见的 因此通过反射是不能直接修改其值的
AtomicMarkableReference类描述的一个Object Boolean的对 可以原子的修改Object或者Boolean的值 这种数据结构在一些缓存或者状态描述中比较有用 这种结构在单个或者同时修改Object/Boolean的时候能够有效的提高吞吐量
AtomicStampedReference类维护带有整数 标志 的对象引用 可以用原子方式对其进行更新 对比AtomicMarkableReference类的Object Boolean AtomicStampedReference维护的是一种类似Object int的数据结构 其实就是对对象(引用)的一个并发计数 但是与AtomicInteger不同的是 此数据结构可以携带一个对象引用(Object) 并且能够对此对象和计数同时进行原子操作
在本文结尾会提到 ABA问题 而AtomicMarkableReference/AtomicStampedReference在解决 ABA问题 上很有用
三 Atomic类的作用
使得让对单一数据的操作 实现了原子化
使用Atomic类构建复杂的 无需阻塞的代码
访问对 个或 个以上的atomic变量(或者对单个atomic变量进行 次或 次以上的操作)通常认为是需要同步的 以达到让这些操作能被作为一个原子单元
无锁定且无等待算法
基于 CAS (pare and swap)的并发算法称为 无锁定算法 因为线程不必再等待锁定(有时称为互斥或关键部分 这取决于线程平台的术语) 无论 CAS 操作成功还是失败 在任何一种情况中 它都在可预知的时间内完成 如果 CAS 失败 调用者可以重试 CAS 操作或采取其他适合的操作
如果每个线程在其他线程任意延迟(或甚至失败)时都将持续进行操作 就可以说该算法是 无等待的 与此形成对比的是 无锁定算法要求仅 某个线程总是执行操作 (无等待的另一种定义是保证每个线程在其有限的步骤中正确计算自己的操作 而不管其他线程的操作 计时 交叉或速度 这一限制可以是系统中线程数的函数 例如 如果有 个线程 每个线程都执行一次CasCounter increment() 操作 最坏的情况下 每个线程将必须重试最多九次 才能完成增加 )
再过去的 年里 人们已经对无等待且无锁定算法(也称为 无阻塞算法)进行了大量研究 许多人通用数据结构已经发现了无阻塞算法 无阻塞算法被广泛用于操作系统和 JVM 级别 进行诸如线程和进程调度等任务 虽然它们的实现比较复杂 但相对于基于锁定的备选算法 它们有许多优点 可以避免优先级倒置和死锁等危险 竞争比较便宜 协调发生在更细的粒度级别 允许更高程度的并行机制等等
常见的
非阻塞的计数器Counter
非阻塞堆栈ConcurrentStack
lishixinzhi/Article/program/Java/gj/201311/27474
什么是原子操作,java中的原子操作是什么
"原子操作(atomic
operation)是不需要synchronized",这是Java多线程编程的老生常谈了。所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何
context
switch
(切[1]
换到另一个线程)。
java原子操作的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于java如何实现原子性、java原子操作的信息别忘了在本站进行查找喔。