我的以为这一节掌握基本的使用便可!
本节思惟导图:java
Atomic 翻译成中文是原子的意思。在化学上,咱们知道原子是构成通常物质的最小单位,在化学反应中是不可分割的。在咱们这里 Atomic 是指一个操做是不可中断的。即便是在多个线程一块儿执行的时候,一个操做一旦开始,就不会被其余线程干扰。数组
因此,所谓原子类说简单点就是具备原子/原子操做特征的类。安全
并发包 java.util.concurrent
的原子类都存放在java.util.concurrent.atomic
下,以下图所示。服务器
根据操做的数据类型,能够将JUC包中的原子类分为4类多线程
基本类型 并发
使用原子的方式更新基本类型this
数组类型阿里云
使用原子的方式更新数组里的某个元素atom
引用类型spa
对象的属性修改类型
下面咱们来详细介绍一下这些原子类。
使用原子的方式更新基本类型
上面三个类提供的方法几乎相同,因此咱们这里以 AtomicInteger 为例子来介绍。
AtomicInteger 类经常使用方法
public final int get() //获取当前的值 public final int getAndSet(int newValue)//获取当前的值,并设置新的值 public final int getAndIncrement()//获取当前的值,并自增 public final int getAndDecrement() //获取当前的值,并自减 public final int getAndAdd(int delta) //获取当前的值,并加上预期的值 boolean compareAndSet(int expect, int update) //若是输入的数值等于预期值,则以原子方式将该值设置为输入值(update) public final void lazySet(int newValue)//最终设置为newValue,使用 lazySet 设置以后可能致使其余线程在以后的一小段时间内仍是能够读到旧的值。
import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerTest { public static void main(String[] args) { // TODO Auto-generated method stub int temvalue = 0; AtomicInteger i = new AtomicInteger(0); temvalue = i.getAndSet(3); System.out.println("temvalue:" + temvalue + "; i:" + i);//temvalue:0; i:3 temvalue = i.getAndIncrement(); System.out.println("temvalue:" + temvalue + "; i:" + i);//temvalue:3; i:4 temvalue = i.getAndAdd(5); System.out.println("temvalue:" + temvalue + "; i:" + i);//temvalue:4; i:9 } }
经过一个简单例子带你们看一下基本数据类型原子类的优点
①多线程环境不使用原子类保证线程安全(基本数据类型)
class Test { private volatile int count = 0; //若要线程安全执行执行count++,须要加锁 public synchronized void increment() { count++; } public int getCount() { return count; } }
②多线程环境使用原子类保证线程安全(基本数据类型)
class Test2 { private AtomicInteger count = new AtomicInteger(); public void increment() { count.incrementAndGet(); } //使用AtomicInteger以后,不须要加锁,也能够实现线程安全。 public int getCount() { return count.get(); } }
AtomicInteger 类的部分源码:
// 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;
AtomicInteger 类主要利用 CAS (compare and swap) + volatile 和 native 方法来保证原子操做,从而避免 synchronized 的高开销,执行效率大为提高。
CAS的原理是拿指望的值和本来的一个值做比较,若是相同则更新成新的值。UnSafe 类的 objectFieldOffset() 方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址,返回值是 valueOffset。另外 value 是一个volatile变量,在内存中可见,所以 JVM 能够保证任什么时候刻任何线程总能拿到该变量的最新值。
使用原子的方式更新数组里的某个元素
上面三个类提供的方法几乎相同,因此咱们这里以 AtomicIntegerArray 为例子来介绍。
AtomicIntegerArray 类经常使用方法
public final int get(int i) //获取 index=i 位置元素的值 public final int getAndSet(int i, int newValue)//返回 index=i 位置的当前的值,并将其设置为新值:newValue public final int getAndIncrement(int i)//获取 index=i 位置元素的值,并让该位置的元素自增 public final int getAndDecrement(int i) //获取 index=i 位置元素的值,并让该位置的元素自减 public final int getAndAdd(int delta) //获取 index=i 位置元素的值,并加上预期的值 boolean compareAndSet(int expect, int update) //若是输入的数值等于预期值,则以原子方式将 index=i 位置的元素值设置为输入值(update) public final void lazySet(int i, int newValue)//最终 将index=i 位置的元素设置为newValue,使用 lazySet 设置以后可能致使其余线程在以后的一小段时间内仍是能够读到旧的值。
import java.util.concurrent.atomic.AtomicIntegerArray; public class AtomicIntegerArrayTest { public static void main(String[] args) { // TODO Auto-generated method stub int temvalue = 0; int[] nums = { 1, 2, 3, 4, 5, 6 }; AtomicIntegerArray i = new AtomicIntegerArray(nums); for (int j = 0; j < nums.length; j++) { System.out.println(i.get(j)); } temvalue = i.getAndSet(0, 2); System.out.println("temvalue:" + temvalue + "; i:" + i); temvalue = i.getAndIncrement(0); System.out.println("temvalue:" + temvalue + "; i:" + i); temvalue = i.getAndAdd(0, 5); System.out.println("temvalue:" + temvalue + "; i:" + i); } }
基本类型原子类只能更新一个变量,若是须要原子更新多个变量,须要使用 引用类型原子类。
上面三个类提供的方法几乎相同,因此咱们这里以 AtomicReference 为例子来介绍。
import java.util.concurrent.atomic.AtomicReference; public class AtomicReferenceTest { public static void main(String[] args) { AtomicReference<Person> ar = new AtomicReference<Person>(); Person person = new Person("SnailClimb", 22); ar.set(person); Person updatePerson = new Person("Daisy", 20); ar.compareAndSet(person, updatePerson); System.out.println(ar.get().getName()); System.out.println(ar.get().getAge()); } } class Person { private String name; private int age; public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
上述代码首先建立了一个 Person 对象,而后把 Person 对象设置进 AtomicReference 对象中,而后调用 compareAndSet 方法,该方法就是经过经过 CAS 操做设置 ar。若是 ar 的值为 person 的话,则将其设置为 updatePerson。实现原理与 AtomicInteger 类中的 compareAndSet 方法相同。运行上面的代码后的输出结果以下:
Daisy 20
若是须要原子更新某个类里的某个字段时,须要用到对象的属性修改类型原子类。
要想原子地更新对象的属性须要两步。第一步,由于对象的属性修改类型原子类都是抽象类,因此每次使用都必须使用静态方法 newUpdater()建立一个更新器,而且须要设置想要更新的类和属性。第二步,更新的对象属性必须使用 public volatile 修饰符。
上面三个类提供的方法几乎相同,因此咱们这里以 AtomicIntegerFieldUpdater
为例子来介绍。
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; public class AtomicIntegerFieldUpdaterTest { public static void main(String[] args) { AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "age"); User user = new User("Java", 22); System.out.println(a.getAndIncrement(user));// 22 System.out.println(a.get(user));// 23 } } class User { private String name; public volatile int age; public User(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
输出结果:
22 23
【强烈推荐】最后,给你们推荐一下阿里云最新双11福利活动(仅限阿里云新用户购买,老用户拉新用户能够得到返现红包,后续有机会平分百万红包),优惠力度很是很是很是大,另外加入拼团,后续还有机会平分100w红包!目前个人战队已经有50多位新人了,如今是折上5折了也就是1折购买,已经达到了最低折扣!!!!!!。 划重点了: 1核2G云服务器1年仅需99.5元!!!1核2G云服务器3年仅需298.50元!!!一个月仅需8.2元 该折扣仅限新人!这是个人团队拼团地址:https://m.aliyun.com/act/team1111/#/share?params=N.FF7yxCciiM.hf47liqn !
另外,老用户能够加入个人战队帮忙拉新,拉新你能够得到什么福利呢?①即时红包,即拆即用(最低红包10元,最高1111元);②瓜分百万红包的机会(目前个人战队已经有29位新人,因此冲进前100的可能性很是大!冲进以后便可瓜分百万红包!)③返现奖励,若是你邀请了新人你会得到返现奖励,返现奖励直接到你的帐户!(我但愿个人团队最后可以冲进前100,别的很少说!!!诚信!)