多線程系列二:原子操做

什麼是原子操做

不可被中斷的一個或者一系列操做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:

違反了面向對象的原則,通常不使用

相關文章
相關標籤/搜索