1. 程式人生 > >多執行緒-Java原子變數-java.util.concurrent.atomic.*

多執行緒-Java原子變數-java.util.concurrent.atomic.*

一個沒有併發控制的計數器:

  1. publicclass Counter implements Runnable {  
  2.     privatestaticint count;  
  3.     publicvoid run() {  
  4.         System.out.println(Thread.currentThread().getName()   
  5.                 + ":" + (++count));  
  6.     }  
  7.     publicstaticvoid main(String[] args){  
  8.         Counter counter = new Counter();  
  9.         Thread t1 = new Thread(counter);  
  10.         Thread t2 = new Thread(counter);  
  11.         Thread t3 = new Thread(counter);  
  12.         Thread t4 = new Thread(counter);  
  13.         t1.start();  
  14.         t2.start();  
  15.         t3.start();  
  16.         t4.start();  
  17.     }  
  18. }  

有時執行正常,但是偶爾會出現如下執行結果:

  1. Thread-1:2  
  2. Thread-0:1  
  3. Thread-2:3  
  4. Thread-3:3  

這顯然和預期結果不太一樣,先用javap -verbose命令分析一下這個類,在位元組碼層面上,++count等價於虛擬機器順次執行如下5條位元組碼指令(不考慮執行期的優化)

  1. getstatic  獲取指定類的靜態域,並將其值壓入棧頂  
  2. iconst_1   將int型1推送至棧頂  
  3. iadd       將棧頂兩int型數值相加並將結果壓入棧頂  
  4. dup        複製棧頂數值並將複製值壓入棧頂  
  5. putstatic  為指定類的靜態域賦值  

當Thread-3執行緒執行getstatic指令時,Thread-2執行緒還未執行至iadd指令,故Thread-3執行緒獲取的初始靜態域count的值和Thread-2執行緒一樣,都為2

本質原因就是++count雖然只是一行程式碼,但這一過程並非原子操作

要保證這種型別的原子操作,可以使用java.util.concurrent.atomic包下的類

  1. 軟體包 java.util.concurrent.atomic   
  2. 類的小工具包,支援在單個變數上解除鎖的執行緒安全程式設計。  

示例如下:

  1. publicclass Counter implements Runnable {  
  2.     privatefinal AtomicInteger count = new AtomicInteger(0);  
  3.     publicvoid run() {  
  4.         System.out.println(Thread.currentThread().getName()   
  5.                 + ":" + count.incrementAndGet());  
  6.     }  
  7.     publicstaticvoid main(String[] args){  
  8.         Counter counter = new Counter();  
  9.         Thread t1 = new Thread(counter);  
  10.         Thread t2 = new Thread(counter);  
  11.         Thread t3 = new Thread(counter);  
  12.         Thread t4 = new Thread(counter);  
  13.         t1.start();  
  14.         t2.start();  
  15.         t3.start();  
  16.         t4.start();  
  17.     }  
  18. }  

看看原始碼中究竟是如何實現的

  1. privatevolatileint value;  
  2. public AtomicInteger(int initialValue) {  
  3.     value = initialValue;  
  4. }  
  5. publicfinalint incrementAndGet() {  
  6.     for (;;) {  
  7.         int current = get();  
  8.         int next = current + 1;  
  9.         if (compareAndSet(current, next))  
  10.             return next;  
  11.     }  
  12. }  
  13. /** 
  14.     * Atomically sets the value to the given updated value 
  15.     * if the current value {@code ==} the expected value. 
  16.     * 
  17.     * @param expect the expected value 
  18.     * @param update the new value 
  19.     * @return true if successful. False return indicates that 
  20.     * the actual value was not equal to the expected value. 
  21.     */
  22. publicfinalboolean compareAndSet(int expect, int update) {  
  23.     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
  24. }  
  25. publicfinalint get() {  
  26.   return value;  
  27. }  

是不是和樂觀鎖很像,如果結果符合預期結果,就將結果返回,否則不斷進行重試,並沒有進行同步,兼顧了安全性和效能

java.util.concurrent.atomic包下還有很多類,使用這些類可以保證對這些類的諸如“獲取-更新”操作是原子性的,從而避發生競態條件

  1. AtomicBoolean 可以用原子方式更新的 boolean 值。   
  2. AtomicInteger 可以用原子方式更新的 int 值。   
  3. AtomicIntegerArray 可以用原子方式更新其元素的 int 陣列。   
  4. AtomicIntegerFieldUpdater<T> 基於反射的實用工具,可以對指定類的指定 volatile int 欄位進行原子更新。   
  5. AtomicLong 可以用原子方式更新的 long 值。   
  6. AtomicLongArray 可以用原子方式更新其元素的 long 陣列。   
  7. AtomicLongFieldUpdater<T> 基於反射的實用工具,可以對指定類的指定 volatile long 欄位進行原子更新。   
  8. AtomicMarkableReference<V> AtomicMarkableReference 維護帶有標記位的物件引用,可以原子方式對其進行更新。   
  9. AtomicReference<V> 可以用原子方式更新的物件引用。   
  10. AtomicReferenceArray<E> 可以用原子方式更新其元素的物件引用陣列。   
  11. AtomicReferenceFieldUpdater<T,V> 基於反射的實用工具,可以對指定類的指定 volatile 欄位進行原子更新。   
  12. AtomicStampedReference<V> AtomicStampedReference 維護帶有整數“標誌”的物件引用,可以用原子方式對其進行更新。   

相關推薦

執行原子變數CAS演算法(二)

上篇博文,我們介紹了多執行緒之記憶體可見性Volatile(一),但是也遺留了一個問題,如何保證變數的”原子性操作(Atomic operations)”? Volatile保證部分型別的原子性 上篇博文,我們說Voloatile不能保證原子性,有一點侷

執行-Java原子變數-java.util.concurrent.atomic.*

一個沒有併發控制的計數器: publicclass Counter implements Runnable {       privatestaticint count;       publicvoid run() {           System.out.

執行學習筆記十三——java中的原子操作類

當程式更新一個變數時,如果多執行緒同時更新這個變數,可能得到期望之外的值,比如變 量i=1,A執行緒更新i+1,B執行緒也更新i+1,經過兩個執行緒操作之後可能i不等於3,而是等於2。因 為A和B執行緒在更新變數i的時候拿到的i都是1,這就是執行緒不安全

java執行之共享變數

目的:簡述java多執行緒的共享變數   共享變數:多個執行緒都會使用到的同一變數。   Q : 為什麼共享變數會造成資料的錯誤呢???       A : 多個執行緒在操作共享變數的時候,不是直接在主記憶體中去操作的。而

java執行的共享變數訪問控制例項

最近打算去一家電商公司,對於高併發的資料訪問控制有著嚴格的要求,近期打算把多執行緒的知識在好好補一下。 執行緒排程有五個狀態; 開始,可執行,執行,阻塞,死亡。 啟動執行緒有兩種方法。繼承Thread類或則實現Runnable介面,其實Thread類也實現

Java執行中static變數的使用 SimpleDateFormat時間格式化存線上程安全問題

兩篇文章 Java多執行緒中static變數的使用  (轉自:http://blog.csdn.net/yy304935305/article/details/52456771) &&  SimpleDateFormat時間格式化存線上程安全問題

Java執行之volatile變數

Java 語言中的 volatile 變數可以被看作是一種 “程度較輕的 synchronized”;與 synchronized 塊相比,volatile 變數所需的編碼較少,並且執行時開銷也較少,但是它所能實現的功能也僅是 synchronized 的一部分。本文介紹了幾種有效使用 volati

Java執行】共享變數&同步-非同步容器&執行區域性變數

共享變數 (Volatile Atomic) volatile:當多個執行緒訪問一個成員變數的時候,需要這個變數在多個執行緒中可見。 Atomic:Atomic方法對該變數的操作是原子性操作,顆粒度是到對這個變數的一次操作。 private stati

Java執行原子操作atomic的使用CAS(七)

3-5、java.util.concurrent.atomic:執行緒安全的原子操作包 在JDK1.5+的版本中,Doug Lea和他的團隊還為我們提供了一套用於保證執行緒安全的原子操作。我們都知道在多執行緒環境下,對於更新物件中的某個屬性、更新基本型別資料、更新陣列(

Java執行操作區域性變數與全域性變數

在這篇文章裡,我們首先闡述什麼是同步,不同步有什麼問題,然後討論可以採取哪些措施控制同步,接下來我們會仿照回顧網路通訊時那樣,構建一個伺服器端的“執行緒池”,JDK為我們提供了一個很大的concurrent工具包,最後我們會對裡面的內容進行探索。   為什麼要執

Java執行與高併發:java.util.concurrent

面試官:你用過JUC的哪些工具類? 前面從基礎開始,到執行緒安全的實現、物件的釋出與共享,涉及到很多執行緒安全的類與工具,JDK1

Java執行原子操作類

在併發程式設計中很容易出現併發安全問題,最簡單的例子就是多執行緒更新變數i=1,多個執行緒執行i++操作,就有可能獲取不到正確的值,而這個問題,最常用的方法是通過Synchronized進行控制來達到執行緒安全的目的。但是由於synchronized是採用的是悲觀鎖策略,並不是特別高效的一種解決方案。實際上,

Java執行——物件及變數的併發訪問

Java多線系列文章是Java多執行緒的詳解介紹,對多執行緒還不熟悉的同學可以先去看一下我的這篇部落格Java基礎系列3:多執行緒超詳細總結,這篇部落格從巨集觀層面介紹了多執行緒的整體概況,接下來的幾篇文章是對多執行緒的深入剖析。   本篇文章主要介紹Java多執行緒中的同步,也就是如何在Java語

java架構之路(執行原子操作,Atomic與Unsafe魔術類

  這次不講原理了,主要是一些應用方面的知識,和上幾次的JUC併發程式設計的知識點更容易理解. 知識回顧:   上次主要說了Semaphore訊號量的使用,就是一個票據的使用,我們舉例了看3D電影拿3D眼鏡的例子,還說了內部的搶3D眼鏡,和後續排隊的原始碼解析,還有CountDownLatch的使用,我們是用

LINUX 執行 JNI 回撥 java static

1.Linux 開啟執行緒 //渲染執行緒Rendering void* thread_rendering_process(void *lParam) {     unsigned int local_wr;     int index; &

java執行系列翻譯之java併發/執行教程

原文地址:http://tutorials.jenkov.com/java-concurrency/index.html 以前計算機都是單核,同時只能執行一個程式。之後出現了多重任務處理,這意味著計算機同時可以處理多個程式(又名任務或流程)。但這不是真正的“同時執行”,只是單個CPU被多個程式共

Java執行(四)java中的Sleep方法

點我跳過黑哥的卑鄙廣告行為,進入正文。 Java多執行緒系列更新中~   正式篇: Java多執行緒(一) 什麼是執行緒 Java多執行緒(二)關於多執行緒的CPU密集型和IO密集型這件事 Java多執行緒(三)如何建立執行緒 Java多執行緒(四)java中的Sleep方法  

執行(二)Java執行,啟動四個執行,兩個執行加一,另外兩個執行減一

  public class Test { public static void main(String[] args) { final ShareData data = new ShareData(); for (int i = 0; i < 2; i++) {

深入理解執行(五)—— Java虛擬機器的鎖優化技術

本文是《深入理解多執行緒》的第五篇文章,前面幾篇文章中我們從synchronized的實現原理開始,一直介紹到了Monitor的實現原理。 前情提要 通過前面幾篇文章,我們已經知道: 1、同步方法通過ACC_SYNCHRONIZED關鍵字隱式的對方法進行加鎖。當執行緒要

java執行:3、Java執行的支援1

宣告:本教程不收取任何費用,歡迎轉載,尊重作者勞動成果,不得用於商業用途,侵權必究!!! 文章目錄 1、Java在語言級提供了對多執行緒程式設計的支援。 2、實現多執行緒程式的兩種方式 3、後臺執行緒 4、yield方法 5、執行緒優先順序 1、Java在語言級提