1. 程式人生 > >Java併發控制synchronized與AtomicInteger類

Java併發控制synchronized與AtomicInteger類

眾所周知,在Java多執行緒程式設計中,一個非常重要的方面就是執行緒的同步問題。關於執行緒的同步,最常用的解決方法就是使用synchronized關鍵字,但是如果使用場景只用在控制一個計數的整型變數時(通常這也是非常常見的一個使用場景),另一種實現方式AtomicInteger類簡潔易用的特性一定會讓你對它愛不釋手。
我們先通過一個簡單的例子模擬下多執行緒併發計數,程式如下

public class ShareData {
	public static int count=0;
	public static void main(String[] args){
		final ShareData data  = new ShareData();
		for(int i=0;i<10;i++){
			new Thread(
					new Runnable(){
						public void run(){
							try{
								Thread.sleep(1);
							}catch(InterruptedException e){
								e.printStackTrace();
							}
							for(int j=0;j<100;j++){
								data.addCount();
							}
							System.out.print(count+" ");
						}
					}
				).start();				
		}
		try{
			Thread.sleep(3000);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		System.out.print("count="+count);
	}
	public void addCount(){
		count++;
	}
}

程式啟動了十個執行緒,每個執行緒計100次數,操作的都是count這個變數,最後在等待3秒(所有執行緒均執行結束後)輸出此時的count值,每次執行後的輸出結果都不一定一樣,但是一般count小於1000,結果如下:

100 224 373 473 373 255 823 791 691 591 count=823

344 566 366 299 299 466 366 669 695 769 count=769

400 400 400 500 400 615 913 813 713 713 count=913

我們將addCount()方法加上synchronized關鍵詞修飾下,讓它實現執行緒安全,

	public synchronized void addCount(){
		count++;
	}


再執行,結果如下:

200 200 411 677 774 864 1000 666 1000 891 count=1000

423 909 1000 428 802 512 691 706 512 914 count=1000

300 500 500 300 300 712 809 850 949 1000 count=1000

此時可以看出最終count的數值都會精確的是1000,講完了synchronized之後我們再來看下AtomicInteger類

AtomicInteger類可以用原子方式更新的 int 值,主要用於在高併發環境下的高效程式處理,使用非阻塞演算法來實現併發控制,它的方法有

//獲取當前的值
public final int get()
//取當前的值,並設定新的值
public final int getAndSet(int newValue)
//獲取當前的值,並自增
public final int getAndIncrement() 
//獲取當前的值,並自減
public final int getAndDecrement()
//獲取當前的值,並加上預期的值
public final int getAndAdd(int delta) 
這裡我們依然用上面的程式做例子,使用AtomicInteger類來替代synchronized方式,程式碼如下:
package concurrent;

import java.util.concurrent.atomic.AtomicInteger;

public class ShareData_AtomicInteger {
	static AtomicInteger count = new AtomicInteger(0);
	public static void main(String[] args){
		final ShareData_AtomicInteger data  = new ShareData_AtomicInteger();
		for(int i=0;i<10;i++){
			new Thread(
					new Runnable(){
						public void run(){
							try{
								Thread.sleep(1);
							}catch(InterruptedException e){
								e.printStackTrace();
							}
							for(int j=0;j<100;j++){
								data.addCount();
							}
							System.out.print(count.get()+" ");
						}
					}
				).start();				
		}
		try{
			Thread.sleep(3000);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		System.out.print("count="+count.get());
	}
	public void addCount(){
		count.getAndIncrement();
	}
}




執行結果如下:

495 528 604 504 987 657 741 682 1000 925 count=1000

500 500 984 823 499 733 500 495 601 1000 count=1000

409 409 436 409 700 587 600 872 988 1000 count=1000

至此結束,AtomicInteger只是concurrent下的一個整數原子操作類,該包下還有很多其他關於執行緒鎖同步的機制,有興趣的同學可以自行搜尋下相關資料~謝謝

相關推薦

Java併發控制synchronizedAtomicInteger

眾所周知,在Java多執行緒程式設計中,一個非常重要的方面就是執行緒的同步問題。關於執行緒的同步,最常用的解決方法就是使用synchronized關鍵字,但是如果使用場景只用在控制一個計數的整型變數時

java併發之----synchronizedReenTrantLock

Java 提供了兩種鎖機制來控制多個執行緒對共享資源的互斥訪問,第一個是 JVM 實現的 synchronized,而另一個是 JDK 實現的 ReentrantLock。 synchronized synchronized關鍵字最主要幾種使用方式: (1)同步一個程式碼塊: 只作用

Java併發學習筆記(九)-原子AtomicInteger

AtomicInteger能夠保證對一個整型的操作是原子性。像i++這個操作不是原子操作,存在競態條件,所以需要加鎖,但是加鎖的效能不高,如果僅僅為了對一個整數加1。我們來看下他的實現。 private volatile int value; AtomicInte

JAVA中的BigIntegerBigDecimal功能強大

取余 並且 log 加減乘除 value java 構造函數 () eof BigInteger類是java為了處理大數字二專門制作的類,可以處理很大的數字(理論上無限大),並且可以實現大數字的類似於int所有數學運算。對算法題來說,再也不怕出現超出int範圍的運算了! 同

JAVA中接口抽象

rac 構造 轉換 希望 就是 pub 成員變量 類型 規則 抽象類總結 抽象類的概念:是使用關鍵字abstract修飾的類就是抽象類; 抽象類的產生:當多個不能相互繼承的類具有相同的功能時,就需要將共同的信息向上抽取,放到公共的父類中;如果公共的父類只能描述所有子類都

Java併發控制:ReentrantLock Condition的使用

生產者-消費者(producer-consumer)問題,也稱作有界緩衝區(bounded-buffer)問題,兩個程序共享一個公共的固定大小的緩衝區。 其中一個是生產者,用於將訊息放入緩衝區;另外一個是消費者,用於從緩衝區中取出訊息。 問題出現在當緩衝區已經滿了,而此時生產者還想

Java併發synchronized之偏向鎖和輕量級鎖

synchronized之偏向鎖和輕量級鎖 上下文切換 synchronized 鎖的升級與對比 偏向鎖 輕量級鎖 參考 上下文切換 即使是單核處理器也支援多執行緒執行程式碼執行程式碼,CPU通

最新Java併發程式設計原理實戰分享

課程大綱第1節你真的瞭解併發嗎?   00:27:48分鐘   | 第2節理解多執行緒與併發的之間的聯絡與區別   00:11:59分鐘   | 第3節解析多執行緒與多程序的聯絡以及上下文切換所

Java併發:CallableFuture

Callable Runnable 封裝一個非同步執行的任務,可以把它想象成為一個沒有引數和返回值的非同步方法。 Runnable runnable = new Runnable() { @Override public void run() { } }; r

Java併發(一)——Thread介紹 .md

1 序言 最近面試期間,發現自己的併發知識比較薄弱,準備寫一個關於併發的系列學習筆記。 2 Thread類主要方法 相信Thread類大家並不陌生,在建立執行緒的時候幾乎都會用到它。下面咱們聊一聊Thread類中的主要方法。 2.1 start方法 開啟一個執行

深入理解Java併發synchronized實現原理

關聯文章: 本篇主要是對Java併發中synchronized關鍵字進行較為深入的探索,這些知識點結合博主對synchronized的個人理解以及相關的書籍的講解(在結尾參考資料),如有誤處,歡迎留言。 執行緒安全是併發程式

Java學習筆記——介面抽象的區別

在某種意義上,介面是比抽象類更抽象的類,介面的作用更多是起到標準化、規範化的作用。 它們之間的區別:   1.抽象類可以有非抽象方法,而介面中只能有抽象方法(但在JDK1.8之後的版本中,介面可以擁有方法體,也就是說,介面也可以擁有非抽象方法了)    2.

Java併發程式設計入門併發面試

第6章 J.U.C之AQS講解 AQS是J.U.C的重要元件,也是面試的重要考點。這一章裡將重點講解AQS模型設計及相關同步元件的原理和使用,都非常實用,具體包括:CountDownLatch、Semaphore、CyclicBarrier、ReentrantLock與鎖、Condition等。這些元

Java併發程式設計原理實戰

推薦視訊連結 java併發程式設計是一個優秀的開發者成長過程中繞不過去的挑戰。資料庫服務,Web服務,大資料處理框架,分散式服務等等,併發程式設計往往扮演著極其重要的角色。天下武功,唯快不破。要想提高效能,併發必不可少。 市面上大多數講解併發的視訊教程大多基於

(七)java併發程式設計synchronized+volatile(安全初始化模式例項)

安全釋出物件的安全性都來自於JMM提供的保證,而造成不正確的釋出原因,就是在”釋出一個共享物件”與”另一個執行緒訪問該物件”之間缺少一種Happen-Before排序. 不安全的釋出 package safe_unsafe_public

(六)java併發程式設計--synchronized同步塊

雖然前面文章的一些例項中已經使用synchronized關鍵字來實現執行緒的同步,但還是需要好好的理解一下。 一段程式碼或者一個方法被synchronized關鍵字標記我們就說這斷程式碼是同步塊。同步塊可以用來避免競爭條件。 synchronize

Java併發程式設計原理實戰一(執行緒狀態及建立執行緒的多種方式)

一、為什麼要學習併發程式設計 1.發揮多處理的強大能力 2.建模的簡單性 3.非同步事件的簡化處理 4.響應更加靈敏的使用者介面 二、併發的缺點 1.安全性問題 多執行緒環境下 多個執行緒共享一個資源 對資源進行非原子性操作 2.活躍

Java-併發-鎖-synchronized

Java-併發-鎖-synchronized 摘要 本文會詳細說下synchronized的底層實現原理。 0x01 基本概念 每次只能有一個執行緒進入臨界區 保證臨界區內共享變數的可見性和有序性 成功進入synchronized區域的執行緒可以拿到物

JAVA學習之StringBuffer Sring的區別(例項展示)

一、字串連線方法不同 String 類中用“+”連線,StringBuffer類中用append()方法連線; 例如如下程式碼: package Test; public class String

Java併發程式設計之原子操作

原子操作類簡介 當更新一個變數的時候,多出現資料爭用的時候可能出現所意想不到的情況。這時的一般策略是使用synchronized解決,因為synchronized能夠保證多個執行緒不會同時更新該變數。然而,從jdk 5之後,提供了粒度更細、量級更輕,並且在多核處理器具有高效