1. 程式人生 > >高階併發程式設計學習-atomic包學習(重點介紹AtomicInteger、AtomicIntegerFieldUpdater)

高階併發程式設計學習-atomic包學習(重點介紹AtomicInteger、AtomicIntegerFieldUpdater)

Java.util.concurrent兩個子包locks&atomic,官網文件介紹為可以對基本資料、陣列中的基本資料、對類中的基本資料進行操作

一 atomic包

1.      原子性定義:原子性意味著個時刻,只有一個執行緒能夠執行一段程式碼,這段程式碼通過一個monitor object保護,從而防止多個執行緒在更新共享狀態時相互衝突。經過atomic類修飾的變數具備原子性,不必考慮在多執行緒併發條件下的執行緒安全問題。

(2)對類中的某個成員變數進行修改

使用方法:

//匯入concurrent包下面的AtomicInteger內容
import java.util.concurrent.atomic.AtomicInteger;

public class TestAtomic {// 測試concurrent包下的AtomicInteger
	public static AtomicInteger i = new AtomicInteger(0);// 所有的執行緒操作同一個物件
	public static int A = 0;

	public static void main(String[] args) throws InterruptedException {
		System.out.println("i累計前"+TestAtomic.i+",A累計前:"+TestAtomic.A);
	Thread t0=	new Thread(
		new Runnable(){

			@Override
			public void run() {
				for(int j=0;j<100000;j++)
				{
					
					TestAtomic.A++;
					TestAtomic.i.getAndIncrement();
				}		
			}
	});
	Thread t1=	new Thread(
				new Runnable(){

					@Override
					public void run() {
						for(int j=0;j<100000;j++)
						{
							
							TestAtomic.A--;
							TestAtomic.i.decrementAndGet();
						}		
					}
			});
	t0.start();
	t1.start();
	t0.join();
	t1.join();
		
		System.out.print("i累計後"+TestAtomic.i+",A累計後:"+TestAtomic.A);
	
}
}


上述程式碼的執行結果為:

i累計前0,A累計前:0

i累計後0,A累計後:24531

從上述程式碼中我們可以看出,變數i保證了結果的正確性,原因在於i採用的是AtomicInteger 屬性,變數具備原子性,從而保證了該變數是執行緒安全的。

(2)對已經new出來的某個變數進行修改,保證其原子性。

AtomicIntegerFieldUpdater使用最重要的在於其建構函式,我們可以在其api檔案中檢視

public static <U> AtomicIntegerFieldUpdater<U>newUpdater(Class<U> tclass,

                                                         

String fieldName)

使用方法:

private AtomicIntegerFieldUpdater<Details>

        atomicIntegerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater(

                Details.class, "numberTimesInvoked" );

詳細使用程式碼:

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

/**
 * volatiles cannot be used directly in operations that do x = x + 1 for
 * numbers can be skipped or duplicated when there are multiple threads
 * involved.
 * <p>
 * Hardware supports Atomic Compare And Swap operations.  CAS java classes
 * like AtomicInteger can use this feature of the hardware to ensure that
 * a "x = x + 1" like operation is atomic.
 * <p>
 * However AtomicInteger is significantly more resource intensive than a simple
 * volatile. If there are many instances of a class which has an AtomicInteger
 * this increase in resource over a volatile can be significant.
 * <p>
 * The AtomicIntegerFieldUpdater comes to the rescue - it can be registered
 * with a volatile variable of a class and can then be used on multiple
 * instances of the class.
 *
 * If there are 1000s of instances of a class which would ordinarily have
 * AtomicInteger this can be a big saving.
 *
 * AtomicIntegerFieldUpdater is able to update a volatile field of an object
 * atomically.
 *
 * @author John Dickerson
 */
public class AtomicIntegerFieldUpdaterCounter {

    // AtomicIntegerFieldUpdater is registered with Details.class so that it
    // knows it will later be updating the volatile field called
    // numberTimesInvoked
	//步驟1 構造方法
    private AtomicIntegerFieldUpdater<Details>
        atomicIntegerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater(
                Details.class, "numberTimesInvoked" );


    /**
     * Diferent threads can call this method to update the volatile field of
     * an instance of Details
     *
     * @param details Details object which has the volatile field called
     * "numberTimesInvoked" in it.
     *
     * @return the value of the counter after it has been incremented by one
     */
    //步驟2 對AtomicIntegerFieldUpdater修飾的變數進行操作
    public int addOne( Details details ){

        // performs a "x = x + 1" style atomic operation
        //return atomicIntegerFieldUpdater.addAndGet( details, 1 );
    	return this.atomicIntegerFieldUpdater.getAndIncrement(details);
    }
    public int subOne(Details details)
    {
    	return atomicIntegerFieldUpdater.decrementAndGet(details);
    }


    /**
     * See test class for example of using this class with multiple threads,
     * some of which are writing to the volatile field and some which are
     * reading from the volatile field
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {

     final    AtomicIntegerFieldUpdaterCounter atomicIntegerFieldUpdaterCounter =
            new AtomicIntegerFieldUpdaterCounter();

        // This call would ordinarily be made by many other threads
     final   Details d=new Details();
        System.out.print("物件d的變數numberTimesInvoked累計前:"+d.getNumberTimesInvoked());
        System.out.println(",A累計前:"+TestAtomic.A);
    	Thread t0=	new Thread(
    		new Runnable(){

    			@Override
    			public void run() {
    				for(int j=0;j<100000;j++)
    				{
    					
    					atomicIntegerFieldUpdaterCounter.addOne(d);
    					TestAtomic.A++;
    				}		
    			}
    	});
    	Thread t1=	new Thread(
    				new Runnable(){

    					@Override
    					public void run() {
    						for(int j=0;j<100000;j++)
    						{
    							TestAtomic.A++;
    							atomicIntegerFieldUpdaterCounter.subOne(d);
    						}		
    					}
    			});
    	t0.start();
    	t1.start();
    	t0.join();
    	t1.join();
    		
    	 System.out.print("物件d的變數numberTimesInvoked累計後:"+d.getNumberTimesInvoked());
         System.out.println(",A累計後:"+TestAtomic.A);
    }
}
/**
 * @author John Dickerson
 */
public class Details {

    volatile int numberTimesInvoked;

    public int getNumberTimesInvoked() {

        return numberTimesInvoked;
    }

    public void setNumberTimesInvoked(int numberTimesInvoked) {

        this.numberTimesInvoked = numberTimesInvoked;
    }
}



執行結果如下:

物件d的變數numberTimesInvoked累計前:0,A累計前:0

物件d的變數numberTimesInvoked累計後:0,A累計後:199947

從上述程式碼中我們可以看出,新建立的:Details d=newDetails();物件d的變數numberTimesInvoked,經過this.atomicIntegerFieldUpdater.getAndIncrement(d); 構造後成了一個執行緒安全的變數。