`
臻是二哥
  • 浏览: 188527 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
博客专栏
Group-logo
Java技术分享
浏览量:0
社区版块
存档分类
最新评论

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类的核心源码:
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问题。
0
2
分享到:
评论
3 楼 zhp8341 2016-07-27  
masuweng 写道
寻求cas的更多例子,

http://www.ccblog.cn/81.htm
2 楼 臻是二哥 2016-07-27  
java.util.concurrent包中到处都使用了CAS和AQS,可以看源码
1 楼 masuweng 2016-07-27  
寻求cas的更多例子,

相关推荐

    尚硅谷JUC视频笔记整理,很详细和全面,帮你迅速掌握JUC

    本笔记整理涉及了JUC的内存可见性、volatile关键字以及CAS算法和原子变量等多个方面,以下是对这些知识点的详细说明。 ### 内存可见性 在多线程环境下,内存可见性是指当一个线程修改了某个共享变量的值,其他线程...

    尚硅谷Java视频_JUC 视频教程

    尚硅谷_JUC线程高级_原子变量与 CAS 算法 ·3. 尚硅谷_JUC线程高级_模拟 CAS 算法 ·4. 尚硅谷_JUC线程高级_同步容器类ConcurrentHashMap ·5. 尚硅谷_JUC线程高级_CountDownLatch 闭锁 ·6. 实现 Callable 接口 ·...

    JUC包含线程,线程池,CAS,volatile等底层原理,以及相关问题的解决方式以及相关工具类的使用

    JUC包括线程、线程池、CAS(Compare and Swap)操作、volatile关键字以及其他相关的底层原理和解决方案。 **synchronized底层原理** synchronized是Java中的内置锁,它在字节码层面表现为monitorenter和monitorexit...

    JUC线程锁框架

    这些类通过CAS(Compare and Swap)算法实现,能够在高并发场景下高效地更新值。 2. **锁机制(Locks)** JUC中的锁机制包括ReentrantLock(可重入锁)、ReadWriteLock(读写锁)等。ReentrantLock相比...

    Java 多线程与并发(8-26)-JUC原子类- CAS, Unsafe和原子类详解.pdf

    Java多线程与并发处理是Java编程中的高级话题,涉及到JUC(java.util.concurrent)包中的原子类、CAS(Compare-And-Swap)机制、Unsafe类以及多线程并发的无锁方案和线程安全的实现方法。 CAS是一种无锁的同步机制...

    Java——JUC

    - `AtomicInteger`、`AtomicLong`等原子类提供了一种在不使用锁的情况下实现线程安全的方式,通过底层的CAS(Compare and Swap)操作保证了原子性,适用于简单的原子更新操作。 5. **Future和Callable接口** - `...

    JUC并发编程与源码分析视频课.zip

    7. **原子类与CAS操作**:介绍AtomicInteger、AtomicLong等原子类,以及无锁编程的基础——Compare and Swap(CAS)操作。理解无锁数据结构的实现和优势。 8. **线程局部变量**:学习ThreadLocal类的使用,了解如何...

    JUC最详细思维导图,一次了解读写锁,可重入锁,Cas原理,volatile 关键字原理

    Java并发编程领域中的Java Util Concurrency (JUC) 工具包提供了丰富的工具类和接口,帮助开发者在多线程环境中高效地管理并发任务。本文将深入探讨其中的关键概念,包括读写锁、可重入锁、CAS原理以及volatile...

    Java多线程(Synchronized+Volatile+JUC 并发工具原理+线程状态+CAS+线程池)

    Java 多线程(Synchronized+Volatile+JUC 并发工具原理+线程状态+CAS+线程池) Java 多线程是 Java 语言中的一种并发编程机制,允许程序同时执行多个线程,以提高程序的执行效率和响应速度。 Java 多线程机制提供了...

    深入分析Java并发编程之CAS

    5. CAS机制:核心功能之一,提供原子的比较并交换操作。 在Java并发包(java.util.concurrent,简称JUC)中,`Unsafe`类被广泛应用于实现高效、无锁的数据结构,如`AtomicInteger`、`AtomicReference`等。这些类的...

    05-Java多线程并发编程JUC.pdf

    根据提供的文档内容,以下是关于Java多线程并发编程与JUC知识点的详细解读: 1. 线程的状态 Java线程在其生命周期中可以拥有不同的状态。线程可能处于以下几种状态: - 新建(New):线程被创建时的状态。 - 就绪...

    AQS和JUC知识点讲解

    线程通过CAS(Compare And Swap)操作来改变这个状态,确保操作的原子性。 2. **等待队列**:AQS内部维护了一个双向链表,作为等待队列。当线程尝试获取资源失败时,会被构建成Node节点并加入到队列中,等待被唤醒...

    谈一谈对JUC的理解Java系列2021.pdf

    总结来说,理解JUC是Java开发者必备的技能之一,它可以帮助我们编写更加高效、安全的并发代码。`volatile`关键字提供了一种相对轻量级的同步机制,但无法解决原子性问题;而原子变量类结合CAS算法,可以解决如`i++`...

    juc从入门到精通实例代码.rar

    - `Atomic*`系列类,如`AtomicInteger`、`AtomicBoolean`等,提供了基于CAS(Compare And Swap)的原子操作,可以在不使用锁的情况下实现线程安全的更新。 5. **线程局部变量** - `ThreadLocal`类,每个线程都有...

    JUC多线程及高并发1

    Java并发编程是提升系统性能和资源利用率的关键技术之一,JUC(Java Concurrency Utilities)是Java平台中的并发工具包,提供了丰富的并发控制和同步机制。本文将深入探讨JUC中的多线程及高并发相关知识点。 一、...

    Java-JUC-多线程 进阶

    Java-JUC-多线程进阶 Java-JUC-多线程进阶resources是 Java 并发编程的高级课程,涵盖了 Java 中的并发编程概念、线程安全、锁机制、集合类、线程池、函数式接口、Stream流式计算等多个方面。 什么是JUC JUC...

    A-JUC-JVM-Java并发知识..pdf

    ### JUC并发编程 #### JUC多线程及高并发 Java并发编程包(java.util.concurrent,简称JUC)封装了大量用于高并发编程的工具类和接口,其中涉及了线程池、阻塞队列、同步器、原子操作类等。在并发环境下,可以有效...

    JUC

    - ConcurrentLinkedQueue:基于链表结构的无界并发队列,采用CAS算法实现,性能较高。 - LinkedBlockingQueue:有界的阻塞队列,基于链表结构,适用于生产者消费者模型。 4. **原子类**: - AtomicInteger,...

    JUC核心类AQS的底层原理

    AQS作为Java并发工具包(JUC)中的一个核心抽象类,其设计目的是为了实现各种同步器(如锁、信号量等)。AQS主要通过三个核心组成部分来实现这些同步组件的功能: 1. **State变量及其CAS操作**:AQS维护了一个名为`...

Global site tag (gtag.js) - Google Analytics