Java 多线程高并发 2 — CAS 无锁

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ocp114/article/details/82824508

在 Java 并发编程里面,最可爱的就是无锁了,非常巧妙,精彩绝伦 额。O__O "…

那么什么是无锁?

  • 顾名思义,在并发情况下采用无锁的方式实现对象操作的原子性,保证数据一致性、安全性、正确性

怎么做?

  • 采用 CAS (Compare And Swap)的方式操作
  • 核心思想是:比对旧数据,如果没人动过或者旧数据和预想的一样,就执行更新等操作
  • 实现的原理是 CAS(V, E, N) ,当且紧当 E = V 时,N 才更新到 V 中,这里的 V 是变量名,E 是期望值,N 是要更新到 V 的值
  • java.util.concurrent.atomic 包下有好几种具体的实现,对象内存空间地址以及偏移量计算比较多,CRUD 惯了,读起来可能有点吃力哈~

那么问题来了

  • 同样需要比对啊,同样有 取值 — 比较 — 更新 的操作啊,多线程情况下,佢完值后别的线程同样可以更新啊,那怎么办?

不用怕

  • 这里的 取值 — 比较 — 更新 的操作是更加底层的系统里面的一条 CPU 指令来完成,主要用到 sun.misc.Unsafe 提供的操作系统硬件级别的原子操作,并不是原来 Java 代码层面上写好几行的操作(好几行代码已经有很多条 CPU 指令了),网络上很多高并发组件都有用到这个

下面是在 AtomicReferenceArray 之上封装了一个简易无锁版本的 Stack

package jvm.concurrent.atomic;

import java.util.concurrent.atomic.AtomicReferenceArray;

public class AtomicStack<E> {
	
    // 用 AtomicReferenceArray 来存放数据
    protected AtomicReferenceArray<E> elementData;
	
    // 用于 栈的扩容,相当于临时变量
    protected AtomicReferenceArray<E> elementDataCopy;

	// 栈中数据数量
    protected int elementCount = 0;

    // 每次扩容的数量
    protected int capacityIncrement = 10;

    public AtomicStack() {
    	elementData = new AtomicReferenceArray<E>(capacityIncrement);
    }

    public E push(E item) {
    	// 先检查容量,不够见扩容
    	ensureCapacity();
    	elementData.set(elementCount, item);
    	elementCount++;
        return elementData.get(elementCount - 1);
    }

    public E pop() {
        if (elementCount == 0) {
            throw new StackOverflowError();
        }
        E item = elementData.getAndSet(--elementCount, null);
        // 检查容量,有多余的就释放掉
        ensureCapacity();
        return item;
    }

    public E peek() {
        if (elementCount == 0) {
            throw new StackOverflowError();
        }
        return elementData.get(elementCount - 1);
    }

    public boolean empty() {
        return elementCount == 0;
    }

    public int search(Object o) {
        for (int i = 0; i < elementData.length(); i++) {
            E item = elementData.get(i);
            if (item == o || o.equals(item)) {
                return i;
            }
        }
        return -1;
    }
    
    /**
     * 判断栈空间大小,不够了就扩容,有多余的就缩小
     */
    private void ensureCapacity() {
        if (elementCount == elementData.length()) {
            elementDataCopy = new AtomicReferenceArray<E>(elementCount + capacityIncrement);
            for (int i = 0; i < elementCount; i++) {
                elementDataCopy.set(i, elementData.get(i));
            }
            elementData = elementDataCopy;
        }else if (elementCount == elementData.length() - capacityIncrement && elementCount > 0) {
            elementDataCopy = new AtomicReferenceArray<E>(elementData.length() - capacityIncrement);
            for (int i = 0; i < elementCount; i++) {
                elementDataCopy.set(i, elementData.get(i));
            }
            elementData = elementDataCopy;
        }
    }
    
}

猜你喜欢

转载自blog.csdn.net/ocp114/article/details/82824508