Java并发编程之原子变量
2017-10-22 13:33
323 查看
原子变量最主要的一个特点就是所有的操作都是原子的,synchronized关键字也可以做到对变量的原子操作。只是synchronized的成本相对较高,需要获取锁对象,释放锁对象,如果不能获取到锁,还需要阻塞在阻塞队列上进行等待。而如果单单只是为了解决对变量的原子操作,建议使用原子变量。关于原子变量的介绍,主要涉及以下内容:
原子变量的基本概念
通过AtomicInteger了解原子变量的基本使用
通过AtomicInteger了解原子变量的基本原理
AtomicReference的基本使用
使用FieldUpdater操作非原子变量的字段属性
经典的ABA问题的解决
一、原子变量的基本概念
原子变量保证了该变量的所有操作都是原子的,不会因为多线程的同时访问而导致脏数据的读取问题。我们先看一段synchronized关键字保证变量原子性的代码:
简单的count++操作,线程对象首先需要获取到Counter 类实例的对象锁,然后完成自增操作,最后释放对象锁。整个过程中,无论是获取锁还是释放锁都是相当消耗成本的,一旦不能获取到锁,还需要阻塞当前线程等等。
对于这种情况,我们可以将count变量声明成原子变量,那么对于count的自增操作都可以以原子的方式进行,就不存在脏数据的读取了。Java给我们提供了以下几种原子类型:
AtomicInteger和AtomicIntegerArray:基于Integer类型
AtomicBoolean:基于Boolean类型
AtomicLong和AtomicLongArray:基于Long类型
AtomicReference和AtomicReferenceArray:基于引用类型
在本文的余下内容中,我们将主要介绍AtomicInteger和AtomicReference两种类型,AtomicBoolean和AtomicLong的使用和内部实现原理几乎和AtomicInteger一样。
二、AtomicInteger的基本使用
首先看它的两个构造函数:
可以看到,我们在通过构造函数构造AtomicInteger原子变量的时候,如果指定一个int的参数,那么该原子变量的值就会被赋值,否则就是默认的数值0。
也有获取和设置这个value值的方法:
当然,这两个方法并不是原子的,所以一般也很少使用,而以下的这些基于原子操作的方法则相对使用的频繁,至于它们的具体实现是怎样的,我们将在本文的后续小节中进行简单的学习。
下面我们实现一个计数器的例子,之前我们使用synchronized实现过,现在我们使用原子变量再次实现该问题。
原子变量的基本概念
通过AtomicInteger了解原子变量的基本使用
通过AtomicInteger了解原子变量的基本原理
AtomicReference的基本使用
使用FieldUpdater操作非原子变量的字段属性
经典的ABA问题的解决
一、原子变量的基本概念
原子变量保证了该变量的所有操作都是原子的,不会因为多线程的同时访问而导致脏数据的读取问题。我们先看一段synchronized关键字保证变量原子性的代码:
public class Counter { private int count; public synchronized void addCount(){ this.count++; } }
简单的count++操作,线程对象首先需要获取到Counter 类实例的对象锁,然后完成自增操作,最后释放对象锁。整个过程中,无论是获取锁还是释放锁都是相当消耗成本的,一旦不能获取到锁,还需要阻塞当前线程等等。
对于这种情况,我们可以将count变量声明成原子变量,那么对于count的自增操作都可以以原子的方式进行,就不存在脏数据的读取了。Java给我们提供了以下几种原子类型:
AtomicInteger和AtomicIntegerArray:基于Integer类型
AtomicBoolean:基于Boolean类型
AtomicLong和AtomicLongArray:基于Long类型
AtomicReference和AtomicReferenceArray:基于引用类型
在本文的余下内容中,我们将主要介绍AtomicInteger和AtomicReference两种类型,AtomicBoolean和AtomicLong的使用和内部实现原理几乎和AtomicInteger一样。
二、AtomicInteger的基本使用
首先看它的两个构造函数:
private volatile int value; public AtomicInteger(int initialValue) { value = initialValue; } public AtomicInteger() { }
可以看到,我们在通过构造函数构造AtomicInteger原子变量的时候,如果指定一个int的参数,那么该原子变量的值就会被赋值,否则就是默认的数值0。
也有获取和设置这个value值的方法:
public final int get() public final void set(int newValue)
当然,这两个方法并不是原子的,所以一般也很少使用,而以下的这些基于原子操作的方法则相对使用的频繁,至于它们的具体实现是怎样的,我们将在本文的后续小节中进行简单的学习。
//基于原子操作,获取当前原子变量中的值并为其设置新值 public final int getAndSet(int newValue) //基于原子操作,比较当前的value是否等于expect,如果是设置为update并返回true,否则返回false public final boolean compareAndSet(int expect, int update) //基于原子操作,获取当前的value值并自增一 public final int getAndIncrement() //基于原子操作,获取当前的value值并自减一 public final int getAndDecrement() //基于原子操作,获取当前的value值并为value加上delta public final int getAndAdd(int delta) //还有一些反向的方法,比如:先自增在获取值的等等
下面我们实现一个计数器的例子,之前我们使用synchronized实现过,现在我们使用原子变量再次实现该问题。
//自定义一个线程类
相关文章推荐
- Java并发编程之原子变量
- Java并发编程之原子变量
- Java并发编程札记-(三)JUC原子类-02原子方式更新单个变量
- Java并发编程-35-原子变量-atomic
- Java并发编程规则:原子变量实现线程安全
- java并发编程实践--原子变量、volatile、synchornized
- 并发编程 21—— 原子变量和非阻塞同步机制
- 【Java多线程编程核心技术】2.对象及变量的并发访问(下)-笔记总结
- Java并发编程实战-----原子性
- 【Java并发编程】之十五:并发编程中实现内存可见的两种方法比较:加锁和volatile变量(r)
- Java多线程编程核心技术---对象及变量的并发访问(一)
- 转: 【Java并发编程】之五:volatile变量修饰符—意料之外的问题(含代码)
- Java多线程编程--(6)学习Java5.0 并发编程包--原子操作的一些类型
- 【Java并发编程】之五:volatile变量修饰符—意料之外的问题(含代码)
- Java多线程编程核心技术---对象及变量的并发访问(二)
- java并发编程之:原子性操作类
- Java并发编程实践笔记之——原子性(Atomicity)
- 【Java并发编程】之十五:并发编程中实现内存可见的两种方法比较:加锁和volatile变量
- JAVA 并发编程-线程范围内共享变量(五)
- Java 8并发教程:原子变量和ConcurrentMap