java 高并发无锁代码_Java高并发-无锁

一、无锁类的原理

1.1 CAS

CAS算法的过程是这样:它包含3个参数CAS(V,E,N)。V表示要更新的变量,E表示预期值,N表示新值。仅当V值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。最后,CAS返回当前V的真实值 。CAS操作是抱着乐观的态度进行的,它总是认为自己可以成功完成操作。当多个线程同时使用CAS操作一个变量时,只有一个会胜出,并成功更新,其余均会失败。失败的线程不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。基于这样的原理,CAS操作即使没有锁,也可以发现其他线程对当前线程的干扰,并进行恰当的处理。

1.2 CPU指令

20180406_002.png

二、无锁类的使用

2.1 AtomicInteger

概述

java.util.concurrent.atomic

public class AtomicInteger extends Number implements java.io.Serializable

主要接口

public final int get() // 获取当前值

public final void set(int newValue) // 设置当前值

public final int getAndSet(int newValue) // 设置新值,并返回旧值

public final boolean compareAndSet(int expect, int u) // 如果当前值为expect,则设置为u

public final int getAndIncrement() // 当前值加1,返回旧值,类似于i++

public final int getAndDecrement() // 当前值减1,返回旧值,类似于i--

public final int getAndAdd(int delta) // 当前值增加delta,返回旧值

public final int incrementAndGet() // 当前值加1,返回新值,类似于++i

public final int decrementAndGet() // 当前值减1,返回新值,类似于--i

public final int addAndGet(int delta) // 当前值增加delta,返回新值

主要接口的实现

// 内部定义了一个value,AtomicInteger只是对它的封装

private volatile int value;

compareAndSet

valueOffset是偏移量

20180406_003.png

20180406_004.png

举例

20180406_005.png

2.2 Unsafe

概述

非安全的操作,比如:根据偏移量设置值

park() 把线程停下来

底层的CAS操作

非公开API,在不同版本的JDK中,可能有较大差异

主要接口

// 获得给定对象偏移量上的int值

public native int getInt(java.lang.Object arg0, long arg1);

// 设置给定对象像偏移量上的int值

public native void putInt(java.lang.Object arg0, long arg1, int arg2);

// 获得字段在对象中的偏移量

public native long objectFieldOffset(Field f);

// 设置给定对象的int值,使用volatile语义

public native void putIntVolatile(Object o, long offset, int x);

// 获得给定对象的int值,使用volatile语义

public native void getIntVolatile(Object o, long offset);

// 和putIntVolatile()一样,但是它要求被操作字段就是volatile类型的

public native void putOrderedInt(Object o, long offset, int x);

2.3 AtomicReference

概述

对引用进行修改

是一个模板类,抽象化了数据类型

主要接口

get()

set(V)

compareAndSet()

getAndSet(V)

举例

20180406_006.png

2.4 AtomicStampedReference

概述

解决ABA问题

一个变量初始值为A

线程1读取变量 00:00

线程2读取变量 00:03

线程2将变量修改为B 00:05

线程3读取变量 00:06

线程3将变量修改为A 00:08

线程1根据变量做计算 00:10

线程1将变量修改为C 00:12 定稿前变量值是A,其实该变量已经经历了ABA的变化

主要接口

// 比较设置 参数依次为:期望值 写入新值 期望时间戳 新时间戳

public boolean compareAndSet(V expectedReference,

V newReference,

int expectedStamp,

int newStamp)

// 获得当前对象引用

public V getReference()

// 获得当前时间戳

public int getStamp()

// 设置当前对象引用和时间戳

public void set(V newReference, int newStamp)

举例

public class AtomicStampedReferenceDemo {

static AtomicStampedReference money = new AtomicStampedReference(19, 0);

public static void main(String[] args) {

// 模拟3个充钱线程,余额小余20时充钱且只充一次

for (int i = 0; i < 3; i++) {

final int timestamp = money.getStamp();

new Thread() {

public void run() {

while (true) {

Integer m = money.getReference();

if (m < 20) {

if (money.compareAndSet(m, m + 20, timestamp, timestamp + 1)) {

System.out.println("余额小于20元,充值成功,余额:" + money.getReference());

}

} else {

// 余额大于20,无需充值

break;

}

}

}

}.start();

}

// 模拟一个消费线程

new Thread() {

public void run() {

// 消费10次,余额大于10元时才能消费

for (int i = 0; i < 10; i++) {

while (true) {

int timestamp = money.getStamp();

Integer m = money.getReference();

if (m > 10) {

if (money.compareAndSet(m, m - 10, timestamp, timestamp + 1)) {

System.out.println("成功消费10元,余额:" + money.getReference());

break;

}

} else {

System.out.println("没有足够的余额");

break;

}

}

try {

Thread.sleep(100);

} catch (InterruptedException e) {

}

}

}

}.start();

}

}

20180406_007.png

2.5 AtomicIntegerArray

概述

支持无锁的数组

主要接口

// 获得数组第i个下标的元素

public final int get(int i)

// 获得数组的长度

public final int length()

// 将数组第i个下标设置为newValue,并返回旧的值

public final int getAndSet(int i, int newValue)

// 进行CAS操作,如果第i个下标的元素等于expect,则设置为update,设置成功返回true

public final boolean compareAndSet(int i, int expect, int update)

// 将第i个下标的元素加1

public final int getAndIncrement(int i)

// 将第i个下标的元素减1

public final int getAndDecrement(int i)

// 将第i个下标的元素增加delta(delta可以是负数)

public final int getAndAdd(int i, int delta)

举例

20180406_008.png

2.6 AtomicIntegerFieldUpdater

概述

让普通变量也享受原子操作

主要接口

// 工厂方法

AtomicIntegerFieldUpdater.newUpdater()

incrementAndGet()

说明

1. Updater只能修改它可见范围内的变量。因为Updater使用反射得到这个变量。如果变量不可见,就会出错。比如如果score声明为private,就是不可行的。

2. 为了确保变量被正确读取,它必须是volatile类型的。如果我们原有代码中未声明这个类型,那么简单声明一个就行,这不会引起什么问题。

3. 由于CAS操作会通过对象实例中的偏移量直接进行赋值,因此它不支持static字段(Unsafe.objectFieldOffset()不支持静态变量)

举例

20180406_009.png

三、无锁算法

3.1 Vector实现

add方法

20180406_010.png

说明

数组实现

modCount++ 记录被修改的次数

ensureCapacityHelper(elementCount+1) 做容量检查

扩容

20180406_011.png

3.2 无锁的Vector实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值