Java 多線程安全之 Atomic

一、 Atomic類簡介
在Java.util.concurrent.atomic包下,有AtomicBoolean , AtomicInteger, AtomicLong, AtomicReference等類,它們的基本特性就是在多線程環境下,執行這些類實例包含的方法時,具有排他性,即當某個線程進入方法,執行其中的指令時,不會被其他線程打斷,而別的線程就像自旋鎖一樣,一直等到該方法執行完成,才由JVM從等待隊列中選擇一個另一個線程進入。
二、例子
以AtomicBoolean爲例,單線程執行普通的方法(如下),不會出現線程問題:

package com.secbro.test.atomic;

/**
 * @author zhuzhisheng
 * @Description
 * @date on 2016/5/26.
 */
public class NormalBoolean implements Runnable{

    public static boolean exits = false;

    private String name;

    public NormalBoolean(String name){
        this.name = name;
    }


    @Override
    public void run() {
        if(!exits){
            exits = true;
            System.out.println(name + ",step 1");
            System.out.println(name + ",step 2");
            System.out.println(name + ",step 3");
            exits = false;
        } else {
            System.out.println(name + ",step else");
        }
    }

    public static void main(String[] args) {
        new NormalBoolean("張三").run();
    }
}

然而,當多線程執行時,就會出現在執行判斷之後的命令時,會有其他線程插入,變更exits的值。如下段代碼:

package com.secbro.test.atomic;

/**
 * @author zhuzhisheng
 * @Description
 * @date on 2016/5/26.
 */
public class NormalBoolean2 implements Runnable{


    public static boolean exits = false;

    private String name;

    public NormalBoolean2(String name) {
        this.name = name;
    }

    @Override
    public void run() {

        if(!exits){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            exits = true;
            System.out.println(name + ",step 1");

            System.out.println(name + ",step 2");

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + ",step 3");
            exits = false;
        } else {
            System.out.println(name + ",step else");
        }

    }
}

然而,當多線程執行時,就會出現在執行判斷之後的命令時,會有其他線程插入,變更exits的值。如下段代碼:

package com.secbro.test.atomic;

/**
 * @author zhuzhisheng
 * @Description
 * @date on 2016/5/26.
 */
public class NormalBoolean2 implements Runnable{


    public static boolean exits = false;

    private String name;

    public NormalBoolean2(String name) {
        this.name = name;
    }

    @Override
    public void run() {

        if(!exits){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            exits = true;
            System.out.println(name + ",step 1");

            System.out.println(name + ",step 2");

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + ",step 3");
            exits = false;
        } else {
            System.out.println(name + ",step else");
        }

    }
}

同時執行兩線程,打印結果爲:

張三,step 1
李四,step 1
張三,step 2
李四,step 2
張三,step 3
李四,step 3

現在,使用AtomicBoolean就可以確保多線程的情況下安全的運行,只有一個線程進行業務處理。

package com.secbro.test.atomic;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author zhuzhisheng
 * @Description
 * @date on 2016/5/26.
 */
public class TestAtomicBoolean implements Runnable{

    public static AtomicBoolean exits = new AtomicBoolean(false);

    private String name;

    public TestAtomicBoolean(String name) {
        this.name = name;
    }

    @Override
    public void run() {

        if(exits.compareAndSet(false,true)){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + ",step 1");

            System.out.println(name + ",step 2");

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + ",step 3");
            exits.set(false);
        } else {
            System.out.println(name + ",step else");
        }

    }
}

當兩個線程執行此類時,打印結果如下:

張三,step else
李四,step 1
李四,step 2
李四,step 3

測試類:

package com.secbro.test.atomic;

/**
 * @author zhuzhisheng
 * @Description
 * @date on 2016/5/26.
 */
public class TestBoolean {
    public static void main(String[] args) {

        Thread thread1 = new Thread(new NormalBoolean2("李四"));
        Thread thread2 = new Thread(new NormalBoolean2("張三"));

        thread1.start();
        thread2.start();

        //-------------------------------------------------------

        Thread thread3 = new Thread(new TestAtomicBoolean("李四"));
        Thread thread4 = new Thread(new TestAtomicBoolean("張三"));

        thread3.start();
        thread4.start();
    }
}

轉載自:http://blog.csdn.net/wo541075754/article/details/51509586

發佈了45 篇原創文章 · 獲贊 31 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章