- 浏览: 188417 次
- 性别:
- 来自: 杭州
博客专栏
-
Java技术分享
浏览量:0
文章分类
最新评论
-
masuweng:
学习了,学习了
mybatis是如何防止SQL注入的 -
somefuture:
终于知道了#$的区别
mybatis是如何防止SQL注入的 -
masuweng:
...
tomct处理请求的流程 -
zhp8341:
<div class="quote_title ...
JUC之CAS -
臻是二哥:
java.util.concurrent包中到处都使用了CAS ...
JUC之CAS
JUC是java.util.concurrent包的简称,该包提供了并发编程的解决方案(当然,JAVA并发编程的解决方案还有synchronized)。从概括的层面来说,JUC包有两大核心:CAS和AQS。其中CAS是java.util.concurrent.atomic包的基础,AQS是java.util.concurrent.locks包以及一些常用类比如Semophore等类的基础。我们先来说说CAS。
CAS的全称为Compare-And-Swap,它是一条CPU并发原语。它的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的。CAS并发原语体现在JAVA语言中就是sun.misc.Unsafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令。这是一种完全依赖于硬件的功能。那么为什么CAS会出现呢?它的作用是怎样的?
实现并发的传统方式是加锁,JAVA中的锁有synchronized和Lock。Lock是基于AQS和CAS实现的,在此先不叙述。对于synchronized锁,JVM在执行它的时候会依赖操作系统的临界区机制。这样的话,每次执行到synchronized锁,都会经历用户态和内核态之间的切换。这个过程的消耗是很大的。而且,大多数时候synchronized锁住的操作是很细粒度的。为了细粒度的操作去经历用户态和内核态之间的切换是低效的做法。
说到这,我想到了线程池。大家知道,当线程创建和销毁的时间大于任务执行的时间时,就需要考虑使用线程池了。但如果和任务执行时间相比,线程创建和销毁的时间很少,那么线程池也可不用。
在synchronized中就是这个问题,当需要同步的操作粒度很细时,使用synchronized是不高效的,这时就有CAS存在的意义了。比如对于i++这种并发计数功能,使用synchronized就大材小用了,而使用CAS来实现就会更加的轻量级,性能更好。因此可以看到java.util.concurrent.atomic包中有类似AtomicInteger这种类。我们来看下AtomicInteger类的核心源码:
在上面的代码中Unsafe类负责执行CAS并发原语,由JVM转化为汇编。在代码中使用CAS自旋volatile变量的形式实现非阻塞并发。这种方式是CAS的主要使用方式。
CAS操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在CAS指令之前返回该位置的值。CAS有效地说明了“我认为位置V应该包含值A;如果包含该值,则将B放到这个位置;否则,不要更改该位置。无论如何,告诉我原值。
Java.util.concurrent.atomic包为开发者提供了比synchronized更加细粒度的并发代码控制方式。实际上也是最细粒度的并发代码控制方式。
CAS是乐观锁,是一种冲突重试的机制,在并发竞争不是很激烈的情况下(也是大多数情况),他的性能要好于基于锁的并发性能。因为并发竞争激烈的话,冲突重试的过程很多。
下面是基于AtomicReference实现的并发的非阻塞栈:
CAS的典型步骤如下:
在上面代码的mark1行,首先获取V的值为A,然后在mark2行会重新判断V的值是否还是A。现实中有这样的情况:在mark1行之后mark2行之前,V的值可能从A变成B又变成A。这个时候,现有的代码仍然认为V的值没有改变,而有些情况下,我们需要识别V的这种改变。这就是ABA问题。
解决ABA问题的一种思路就是在CAS操作的时候更新两个值,包括引用和该值的版本号,JUC中提供了这个类AtomicStampedReferance以及AtomicMarkedReference。这两个类支持在两个变量上执行CAS操作,用于解决ABA问题。
CAS的全称为Compare-And-Swap,它是一条CPU并发原语。它的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的。CAS并发原语体现在JAVA语言中就是sun.misc.Unsafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令。这是一种完全依赖于硬件的功能。那么为什么CAS会出现呢?它的作用是怎样的?
实现并发的传统方式是加锁,JAVA中的锁有synchronized和Lock。Lock是基于AQS和CAS实现的,在此先不叙述。对于synchronized锁,JVM在执行它的时候会依赖操作系统的临界区机制。这样的话,每次执行到synchronized锁,都会经历用户态和内核态之间的切换。这个过程的消耗是很大的。而且,大多数时候synchronized锁住的操作是很细粒度的。为了细粒度的操作去经历用户态和内核态之间的切换是低效的做法。
说到这,我想到了线程池。大家知道,当线程创建和销毁的时间大于任务执行的时间时,就需要考虑使用线程池了。但如果和任务执行时间相比,线程创建和销毁的时间很少,那么线程池也可不用。
在synchronized中就是这个问题,当需要同步的操作粒度很细时,使用synchronized是不高效的,这时就有CAS存在的意义了。比如对于i++这种并发计数功能,使用synchronized就大材小用了,而使用CAS来实现就会更加的轻量级,性能更好。因此可以看到java.util.concurrent.atomic包中有类似AtomicInteger这种类。我们来看下AtomicInteger类的核心源码:
public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; // setup to use Unsafe.compareAndSwapInt for updates private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } private volatile int value; public AtomicInteger(int initialValue) { value = initialValue; } public AtomicInteger() { } public final int get() { return value; } public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } } }
在上面的代码中Unsafe类负责执行CAS并发原语,由JVM转化为汇编。在代码中使用CAS自旋volatile变量的形式实现非阻塞并发。这种方式是CAS的主要使用方式。
CAS操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在CAS指令之前返回该位置的值。CAS有效地说明了“我认为位置V应该包含值A;如果包含该值,则将B放到这个位置;否则,不要更改该位置。无论如何,告诉我原值。
Java.util.concurrent.atomic包为开发者提供了比synchronized更加细粒度的并发代码控制方式。实际上也是最细粒度的并发代码控制方式。
CAS是乐观锁,是一种冲突重试的机制,在并发竞争不是很激烈的情况下(也是大多数情况),他的性能要好于基于锁的并发性能。因为并发竞争激烈的话,冲突重试的过程很多。
下面是基于AtomicReference实现的并发的非阻塞栈:
import java.util.concurrent.atomic.AtomicReference; public class ConcurrentStack <E>{ private AtomicReference<Node<E>> top=new AtomicReference<Node<E>>(); public void push(E value){ Node<E> newTop=new Node<E>(value); Node<E> oldTop=null; do{ oldTop=top.get(); newTop.next=oldTop; }while(!top.compareAndSet(oldTop,newTop)); } public E pop(){ Node<E> node=null; Node<E> newTop=null; do{ node=top.get(); if(node==null) return null; newTop=node.next; node.next=null; }while(!top.compareAndSet(node, newTop)); return node.value; } private class Node<E>{ public Node<E> next; public final E value; public Node(E value){ this.value=value; } } }
CAS的典型步骤如下:
while(true){ int A=V.get();//mark1 if(A==V.compareAndSwap(A,newA))//mark2 return A; }
在上面代码的mark1行,首先获取V的值为A,然后在mark2行会重新判断V的值是否还是A。现实中有这样的情况:在mark1行之后mark2行之前,V的值可能从A变成B又变成A。这个时候,现有的代码仍然认为V的值没有改变,而有些情况下,我们需要识别V的这种改变。这就是ABA问题。
解决ABA问题的一种思路就是在CAS操作的时候更新两个值,包括引用和该值的版本号,JUC中提供了这个类AtomicStampedReferance以及AtomicMarkedReference。这两个类支持在两个变量上执行CAS操作,用于解决ABA问题。
评论
3 楼
zhp8341
2016-07-27
2 楼
臻是二哥
2016-07-27
java.util.concurrent包中到处都使用了CAS和AQS,可以看源码
1 楼
masuweng
2016-07-27
寻求cas的更多例子,
发表评论
-
精心准备的讲解Java多线程的知乎Live
2018-09-02 21:39 704花了一个月的时间,结合自己的理解,制作了一个以图片的方式讲解J ... -
在知乎推出Java求职类专栏文章
2018-08-27 12:06 790从昨天起,笔者开始在知乎推出Java求职类专栏文章,主要涉及一 ... -
JUC之AQS
2016-07-27 15:49 1271AQS是同步框架,它进行 ... -
JAVA并发-线程状态和线程组
2016-07-18 14:14 1319在Java中,线程有6种基本状态,理解这6种基本状态之间的关系 ... -
JAVA并发-条件队列
2016-07-02 09:57 1115在JVM系列博客http://yizhen ... -
JAVA并发-中断处理和任务取消
2016-06-27 22:42 1286中断处理 在java程序中 ... -
JAVA并发-显式锁(二)
2016-06-06 09:25 1024在上一篇博客《JAVA并发-显式锁(一)》中介绍了Lock和R ... -
JAVA并发-显式锁(一)
2016-06-05 20:40 891JAVA语言除了提供内置锁synchronized,还在JDK ... -
JAVA并发-减少锁的竞争
2016-06-04 16:01 1904降低锁的竞争可以提高 ... -
JAVA并发-3种典型的死锁
2016-06-03 19:54 1621在JAVA并发编程中,我们 ... -
JAVA并发-3种典型的死锁
2016-06-03 10:02 10在JAVA并发编程中,我们 ... -
JAVA并发-ThreadPoolExecutor线程池的使用
2016-05-30 16:19 2356在博客JAVA并发-Executor任务执行框架中曾说过,Ex ... -
JAVA并发-Executor任务执行框架
2016-05-27 19:10 432首先介绍两个重要的接 ... -
JAVA并发-DCL与JMM
2016-04-26 19:21 1615首先必须声明,在volatil ... -
JAVA并发- 典型连接池的实现
2016-04-22 10:44 1224package com.xyz.connpool; pu ... -
JAVA并发-构建可靠的结果缓存
2016-04-10 16:58 55在学习了前面关于多线程的博客之后,下面来介绍一个构建可靠结果缓 ... -
JAVA并发-并发编程常用类
2016-04-08 11:07 991在讲同步工具类之前,笔者想先介绍一下Runnable,Call ... -
JAVA并发-同步容器和并发容器
2016-04-07 19:02 698常见的同步容器类包括V ... -
JAVA并发-开发线程安全类
2016-04-01 10:23 840我们知道,面向对象的 ... -
JAVA并发-为现有的线程安全类添加原子方法
2016-03-30 20:46 1439JAVA中有许多线程安全的基础模块类,一般情况下,这些基础模块 ...
相关推荐
本笔记整理涉及了JUC的内存可见性、volatile关键字以及CAS算法和原子变量等多个方面,以下是对这些知识点的详细说明。 ### 内存可见性 在多线程环境下,内存可见性是指当一个线程修改了某个共享变量的值,其他线程...
尚硅谷_JUC线程高级_原子变量与 CAS 算法 ·3. 尚硅谷_JUC线程高级_模拟 CAS 算法 ·4. 尚硅谷_JUC线程高级_同步容器类ConcurrentHashMap ·5. 尚硅谷_JUC线程高级_CountDownLatch 闭锁 ·6. 实现 Callable 接口 ·...
JUC包括线程、线程池、CAS(Compare and Swap)操作、volatile关键字以及其他相关的底层原理和解决方案。 **synchronized底层原理** synchronized是Java中的内置锁,它在字节码层面表现为monitorenter和monitorexit...
这些类通过CAS(Compare and Swap)算法实现,能够在高并发场景下高效地更新值。 2. **锁机制(Locks)** JUC中的锁机制包括ReentrantLock(可重入锁)、ReadWriteLock(读写锁)等。ReentrantLock相比...
Java多线程与并发处理是Java编程中的高级话题,涉及到JUC(java.util.concurrent)包中的原子类、CAS(Compare-And-Swap)机制、Unsafe类以及多线程并发的无锁方案和线程安全的实现方法。 CAS是一种无锁的同步机制...
- `AtomicInteger`、`AtomicLong`等原子类提供了一种在不使用锁的情况下实现线程安全的方式,通过底层的CAS(Compare and Swap)操作保证了原子性,适用于简单的原子更新操作。 5. **Future和Callable接口** - `...
7. **原子类与CAS操作**:介绍AtomicInteger、AtomicLong等原子类,以及无锁编程的基础——Compare and Swap(CAS)操作。理解无锁数据结构的实现和优势。 8. **线程局部变量**:学习ThreadLocal类的使用,了解如何...
Java并发编程领域中的Java Util Concurrency (JUC) 工具包提供了丰富的工具类和接口,帮助开发者在多线程环境中高效地管理并发任务。本文将深入探讨其中的关键概念,包括读写锁、可重入锁、CAS原理以及volatile...
Java 多线程(Synchronized+Volatile+JUC 并发工具原理+线程状态+CAS+线程池) Java 多线程是 Java 语言中的一种并发编程机制,允许程序同时执行多个线程,以提高程序的执行效率和响应速度。 Java 多线程机制提供了...
5. CAS机制:核心功能之一,提供原子的比较并交换操作。 在Java并发包(java.util.concurrent,简称JUC)中,`Unsafe`类被广泛应用于实现高效、无锁的数据结构,如`AtomicInteger`、`AtomicReference`等。这些类的...
根据提供的文档内容,以下是关于Java多线程并发编程与JUC知识点的详细解读: 1. 线程的状态 Java线程在其生命周期中可以拥有不同的状态。线程可能处于以下几种状态: - 新建(New):线程被创建时的状态。 - 就绪...
线程通过CAS(Compare And Swap)操作来改变这个状态,确保操作的原子性。 2. **等待队列**:AQS内部维护了一个双向链表,作为等待队列。当线程尝试获取资源失败时,会被构建成Node节点并加入到队列中,等待被唤醒...
总结来说,理解JUC是Java开发者必备的技能之一,它可以帮助我们编写更加高效、安全的并发代码。`volatile`关键字提供了一种相对轻量级的同步机制,但无法解决原子性问题;而原子变量类结合CAS算法,可以解决如`i++`...
- `Atomic*`系列类,如`AtomicInteger`、`AtomicBoolean`等,提供了基于CAS(Compare And Swap)的原子操作,可以在不使用锁的情况下实现线程安全的更新。 5. **线程局部变量** - `ThreadLocal`类,每个线程都有...
Java并发编程是提升系统性能和资源利用率的关键技术之一,JUC(Java Concurrency Utilities)是Java平台中的并发工具包,提供了丰富的并发控制和同步机制。本文将深入探讨JUC中的多线程及高并发相关知识点。 一、...
Java-JUC-多线程进阶 Java-JUC-多线程进阶resources是 Java 并发编程的高级课程,涵盖了 Java 中的并发编程概念、线程安全、锁机制、集合类、线程池、函数式接口、Stream流式计算等多个方面。 什么是JUC JUC...
### JUC并发编程 #### JUC多线程及高并发 Java并发编程包(java.util.concurrent,简称JUC)封装了大量用于高并发编程的工具类和接口,其中涉及了线程池、阻塞队列、同步器、原子操作类等。在并发环境下,可以有效...
- ConcurrentLinkedQueue:基于链表结构的无界并发队列,采用CAS算法实现,性能较高。 - LinkedBlockingQueue:有界的阻塞队列,基于链表结构,适用于生产者消费者模型。 4. **原子类**: - AtomicInteger,...
AQS作为Java并发工具包(JUC)中的一个核心抽象类,其设计目的是为了实现各种同步器(如锁、信号量等)。AQS主要通过三个核心组成部分来实现这些同步组件的功能: 1. **State变量及其CAS操作**:AQS维护了一个名为`...