Javaマルチスレッド-新しいフィーチャー-原子量

4334 ワード

いわゆる原子量,すなわち操作変数の操作は「原子的」であり,この操作は再分割できないためスレッドが安全である.なぜ原子変数を使用するのかは、複数のスレッドが単一の変数に対して操作してもいくつかの問題が発生するためです.Java 5の前にvolatile、synchronizedキーワードで同時アクセスのセキュリティ問題を解決できますが、これは面倒です.Java 5以降、単一変数マルチスレッドの同時セキュリティアクセスを行うためのツールパッケージjavaが提供する.util.concurrent.atomic、その中のクラスも簡単です.
package cn.thread;

import java.util.concurrent.atomic.AtomicLong;

public class AtomicRunnable implements Runnable {
    private static AtomicLong aLong = new AtomicLong(10000); //  , 
    private String name; //  
    private int x; //  

    AtomicRunnable(String name, int x) {
        this.name = name;
        this.x = x;
    }

    public void run() {
        System.out.println(name + " " + x + ", :" + aLong.addAndGet(x));
    }

}
package cn.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;

/**
 *  - 
 * 
 * @author  
 * @version 1.0 2013-7-26  04:13:45
 */
public class ThreadAtomicTest {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        Runnable t1 = new AtomicRunnable(" ", 2000);
        Runnable t2 = new AtomicRunnable(" ", 3600);
        Runnable t3 = new AtomicRunnable(" ", 2700);
        Runnable t4 = new AtomicRunnable(" ", 600);
        Runnable t5 = new AtomicRunnable(" ", 1300);
        Runnable t6 = new AtomicRunnable(" ", 800);
        //  
        pool.execute(t1);
        pool.execute(t2);
        pool.execute(t3);
        pool.execute(t4);
        pool.execute(t5);
        pool.execute(t6);
        //  
        pool.shutdown();
    }

     
}
 2000, :12000
 2700, :14700
 600, :15300
 1300, :16600
 800, :17400
 3600, :21000
 2000, :12000
 3600, :15600
 600, :18900
 1300, :20200
 800, :21000
 2700, :18300
 2000, :12000
 2700, :14700
 3600, :18300
 1300, :20200
 800, :21000
 600, :18900

実行結果から,原子量を用いたにもかかわらずプログラムの同時アクセスに問題があることが分かるが,それはいったいどこに問題があるのか.ここで注意しなければならないのは、原子量は、単一の変数の操作プロセスの安全を保証することができますが、コードブロック全体、またはプログラム全体の安全性を保証することはできません.したがって、通常、ロックなどの同期メカニズムを使用して、プログラム全体のセキュリティを制御する必要があります.次は、このエラーの修正です.
package cn.thread;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;

public class AtomicRunnable2 implements Runnable {
    private static AtomicLong aLong = new AtomicLong(10000); //  , 
    private String name; //  
    private int x; //  
    private Lock lock;

    AtomicRunnable2(String name, int x, Lock lock) {
        this.name = name;
        this.x = x;
        this.lock=lock;
    }

    public void run() {
        lock.lock();
        System.out.println(name + " " + x + ", :" + aLong.addAndGet(x));
        lock.unlock();
    }

}
package cn.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 *  - 
 * 
 * @author  
 * @version 1.0 2013-7-26  04:13:45
 */
public class ThreadAtomicTest2 {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        Lock lock = new ReentrantLock(false);
        Runnable t1 = new AtomicRunnable2(" ", 2000, lock);
        Runnable t2 = new AtomicRunnable2(" ", 3600, lock);
        Runnable t3 = new AtomicRunnable2(" ", 2700, lock);
        Runnable t4 = new AtomicRunnable2(" ", 600, lock);
        Runnable t5 = new AtomicRunnable2(" ", 1300, lock);
        Runnable t6 = new AtomicRunnable2(" ", 800, lock);
        //  
        pool.execute(t1);
        pool.execute(t2);
        pool.execute(t3);
        pool.execute(t4);
        pool.execute(t5);
        pool.execute(t6);
        //  
        pool.shutdown();
    }

}
 3600, :13600
 2700, :16300
 600, :16900
 1300, :18200
 800, :19000
 2000, :21000

ここでは、同時コードへのアクセスを制御するオブジェクトロックを使用します.何回実行しても、実行順序にかかわらず、最終残高は21000であり、この結果は正しい.原子量の使い方は簡単で,原子量の認識が鍵であり,原子は変数操作の原子性を保証するだけであるが,プログラム全体はスレッドの安全を考慮する必要がある.