多线程系列二:原子操做

什么是原子操做

不可被中断的一个或者一系列操做java

实现原子操做的方式

Java能够经过锁和循环CAS的方式实现原子操做面试

CAS( Compare And Swap )  为何要有CAS?

Compare And Swap就是比较而且交换的一个原子操做,由Cpu在指令级别上进行保证。数组

为何要有CAS:由于经过锁实现原子操做时,其余线程必须等待已经得到锁的线程运行完之后才能得到资源,这样就会占用系统的大量资源安全

CAS包含哪些参数?

CAS包含三个参数:1、变量所在内存地址V2、变量对应的值A3、咱们将要修改的值B。若是说V上的变量的值是A的话,就用B从新赋值,若是不是A,那就什么事也不作,操做的返回结果原值是多少。this

循环CAS:在一个(死)循环【for(;;)】里不断进行CAS操做,直到成功为止(自旋操做即死循环)。atom

CAS实现原子操做的三大问题

一、 ABA问题:其余的线程把值改为了B,很快改为了A,原子操做的线程发现值是A就修改,这样会有问题。解决ABA,引入版本号:1A-2C-3Aspa

二、 循环时间很长的话,cpu的负荷比较大线程

三、 对一个变量进行操做能够,同时操做多个共享变量有点麻烦code

CAS线程安全面试点

经过硬件层面的阻塞实现原子操做的安全对象

原子更新基本类型类

AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference

AtomicInteger的经常使用方法以下

·int addAndGet(int delta): 

·boolean compareAndSet(int expect,int update): 

·int getAndIncrement(): 原子递增,可是返回的是自增之前的值

incrementAndGet原子递增,可是返回的是自增之后的值

·int getAndSet(int newValue): 

 1 package com.lgs.atomicint;  2 
 3 import java.util.concurrent.atomic.AtomicInteger;  4 
 5 /**
 6  * lgs  7  * 原子操做更新整型  8  */
 9 public class AtomicIntTest { 10     static AtomicInteger ai = new AtomicInteger(1); 11     public static void main(String[] args) { 12  System.out.println(ai.getAndIncrement()); 13  ai.incrementAndGet(); 14  System.out.println(ai.get()); 15  } 16 }

输出:

1
3

原子更新数组类

AtomicIntegerArrayAtomicLongArrayAtomicReferenceArray

AtomicIntegerArray类主要是提供原子的方式更新数组里的整型,

其经常使用方法以下。

·int addAndGet(int i,int delta): 

·boolean compareAndSet(int i,int expect,int update): 

数组经过构造方法传入,类会将数组复制一份,原数组不会发生变化。

 1 package com.lgs.atomicarray;  2 
 3 import java.util.concurrent.atomic.AtomicIntegerArray;  4 
 5 /**
 6  * lgs  7  * 原子操做更新数组  8  */
 9 public class AtomicArray { 10     static int[] value = new int[]{1,2}; 11     static AtomicIntegerArray ai = new AtomicIntegerArray(value); 12 
13     public static void main(String[] args) { 14         ai.getAndSet(0,3); 15         System.out.println(ai.get(0)); 16         System.out.println(value[0]); 17  } 18 
19 }

输出:

3
1

原子更新引用类型提供的类。

·AtomicReference 能够解决更新多个变量的问题

·AtomicStampedReference:解决ABA问题 使用数字做为版本 关心得是有几我的改过

·AtomicMarkableReference:解决ABA问题 使用Boolean做为版本,关心的是有没有修改过

 1 package com.lgs;  2 
 3 import java.util.concurrent.atomic.AtomicReference;  4 
 5 /**
 6  * lgs  7  * 原子操做更新引用类型便可以同时更新多个值  8  */
 9 public class AtomicRef { 10 
11     static AtomicReference<User> userAtomicReference = new AtomicReference<>(); 12 
13     public static void main(String[] args) { 14         User user = new User("lgs",26); 15  userAtomicReference.set(user); 16         User updateUser = new User("ll",27); 17  userAtomicReference.compareAndSet(user,updateUser); 18  System.out.println(userAtomicReference.get().getName()); 19  System.out.println(userAtomicReference.get().getOld()); 20  } 21 
22     static class User{ 23         private String name; 24         private int old; 25 
26         public User(String name, int old) { 27             this.name = name; 28             this.old = old; 29  } 30 
31         public String getName() { 32             return name; 33  } 34 
35         public int getOld() { 36             return old; 37  } 38  } 39 
40 }

输出:

ll
27

原子更新字段类

Atomic包提供了如下3个类进行原子字段更新。

·AtomicReferenceFieldUpdater: 

·AtomicIntegerFieldUpdater: 

·AtomicLongFieldUpdater:

违反了面向对象的原则,通常不使用

相关文章
相关标签/搜索