1. 程式人生 > >Java原子類Atomic原理和應用

Java原子類Atomic原理和應用

jdk所提供的原子類可以大致分為四種類型:

  1. 原子更新基本資料型別
  2. 原子更新陣列型別
  3. 原子更新抽象資料型別
  4. 原子更新欄位
     

先來看看jdk提供的原子類(rt.jar包下java.util.concurrent.atomic):

首先我們來寫一個數字自增生成器

package cn.itcats.thread.safe.Test1;

public class Sequence {
	private int a = 0;

	public  int add() {
		return a++;
	}

	public static void main(String[] args) {
		Sequence sequence = new Sequence();
		new Thread(new Runnable() {
			public void run() {
				while (true) {
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "   " + sequence.add());
				}
			}
		}).start();

		new Thread() {
			public void run() {
				while (true) {
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "   " + sequence.add());
				}
			};
		}.start();

	}
}

列出部分的執行結果:

Thread-0   0
Thread-1   0
Thread-1   1
Thread-0   1
Thread-1   2
Thread-0   3
Thread-1   4
Thread-0   5

明顯可見存線上程安全問題,這也就是我們正需要解決的問題

add()方法中   a++;    並不是一個原子性操作,我們使用原子類把int a變成一個原子類

package cn.itcats.thread.safe.Test1;

import java.util.concurrent.atomic.AtomicInteger;

public class Sequence {
	//使用原子類AtomicInteger
	private AtomicInteger a = new AtomicInteger(0);

	public  int add() {
		return a.getAndIncrement();   //先獲取再自增,對應a++   
		//若使用++a 則對應方法是a.incrementAndGet(); 先自增再獲取 , 
		//多說一句  a-- 就是  a.getAndDecrement();   
		//若a = a + 10;————對應API  a.getAndAdd(10);
	}

	public static void main(String[] args) {
		Sequence sequence = new Sequence();
		new Thread(new Runnable() {
			public void run() {
				while (true) {
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "   " + sequence.add());
				}
			}
		}).start();

		new Thread() {
			public void run() {
				while (true) {
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "   " + sequence.add());
				}
			};
		}.start();

	}
}

再看執行結果發現,並沒有出現重複的數字。因此我們對數值的一些非原子性操作,都可以使用原子類轉化為原子性操作。

除了對int等基本資料型別的操作,還可以對陣列使用原子類進行原子性操作。

private int[] s = {1,2,3};
AtomicIntegerArray array = new AtomicIntegerArray(s);
public int arrayAdd() {
		return array.getAndAdd(0, 10);
	}

對原子更新抽象資料型別進行設定和獲取    AtomicReference<User> at = new AtomicReference<User>();

原子更新欄位 如更新User欄位屬性  

AtomicIntegerFieldUpdater<User> userAto = AtomicIntegerFieldUpdater.newUpdater(User.class,"name");

相關API不一一說明了,因為用的不算太多。