【Java并发编程 线程安全】15.Atomic原子类和CAS算法

前言

在使用volatile关键字后,并不会完全解决线程安全问题,它只是解决线程可见性问题。
jdk1.5后推出了并发包:java.util.concurrent.atomic可以解决线程原子性的问题。

常用方法

  • get 具有读取 volatile 变量的内存效果。
  • set 具有写入(分配)volatile 变量的内存效果。
  • weakCompareAndSet 以原子方式读取和有条件地写入变量但不 创建任何 happen-before 排序,因此不提供与除 weakCompareAndSet 目标外任何变量以前或后续读取或写入操作有关的任何保证。
  • compareAndSet 和所有其他的读取和更新操作(如 getAndIncrement)都有读取和写入 volatile 变量的内存效果。

volatile出现的问题

public class ThreadAtomic{
 
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        for (int i = 0;i<1000;i++) {
            new Thread(ticket).start();
        }
    }
}
class Ticket implements Runnable{
    public volatile int count = 0;
    @Override
    public void run() {
        count++;
        System.out.println("当前线程:"+Thread.currentThread().getName()+":"+count);
    }
}

依然存在数据问题
打印如下:

当前线程:Thread-933:920
当前线程:Thread-913:915
当前线程:Thread-912:914
当前线程:Thread-925:913
当前线程:Thread-924:912

i++的原子性问题:i++ 的操作实际分了三个步骤“读-改-写”
atomic特性

  • 里面的变量全部用volatile关键值修饰,保证内存可见性
  • CAS(Compare-And-Swap)算法保证数据的原子性(CAS算法是硬件对于并发操作共享数据的支持,jvm底层大量的支持)
    CAS包含三个操作数:内存值 V,预估值 A,更新值 B 。如果 V == A 时,V = B 。否则,不做任何操作。

Atomic类解决原子性

在java.util.concurrent.atomic可以解决线程原子性的问题 , 类如下:

AtomicBoolean
AtomicInteger
AtomicIntegerArray
AtomicIntegerFieldUpdater
AtomicLong
AtomicLongArray
AtomicLongFieldUpdater
AtomicMarkableReference
AtomicReference
AtomicReferenceArray
AtomicReferenceFieldUpdater
AtomicStampedReference
DoubleAccumulator
DoubleAdder
LongAccumulator
LongAdder
Striped64

使用AtomicInteger

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadAtomic{

	public static void main(String[] args) {
		Ticket ticket = new Ticket();
		for (int i = 0;i<1000;i++) {
			new Thread(ticket).start();
		}
	}
}
class Ticket implements Runnable{
	
	// public volatile int count = 0;
	
	public AtomicInteger count = new AtomicInteger(0);
	
	@Override
	public void run() {
		// System.out.println("当前线程:"+Thread.currentThread().getName()+":"+count++);
		// 相当于count++
		System.out.println("当前线程:"+Thread.currentThread().getName()+":"+count.getAndIncrement());
	}	
}

打印如下:

当前线程:Thread-992992
当前线程:Thread-994993
当前线程:Thread-993994
当前线程:Thread-995995
当前线程:Thread-996996
当前线程:Thread-998997
当前线程:Thread-999998
当前线程:Thread-997999

模拟CAS算法

/** 
 * 模拟CAS算法
 * @author terry
 * @date 2018年5月26日 
 */
public class TestCompareAndSwap {
	public static void main(String[] args) {
		final CompareAndSwap cas = new CompareAndSwap();
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					int expectedValue = cas.get();
					boolean b = cas.compareAndSet(expectedValue, (int)(Math.random() * 101));
					System.out.println(b);
				}
			}).start();
		}
	}
}
class CompareAndSwap{
	
	private volatile int value;
	
	public synchronized int get(){
		return value;
	}
	
	public synchronized int compareAndSwap(int expectedValue,int newValue){
		int oldValue = value;
		if (expectedValue == oldValue) {
			this.value = newValue;
		}
		return oldValue;
	}
	
	public synchronized boolean compareAndSet(int expectedValue,int newValue){
		return expectedValue == compareAndSwap(expectedValue,newValue);
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

terrybg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值