天天看點

java中Atomic類之AtomicBooleanjava中Atomic類之AtomicBoolean類舉例說明1、單線程2、多線程3、AtomicBoolean多線程

java中Atomic類之AtomicBoolean

在java.util.concurrent.atomic包下,有AtomicBoolean , AtomicInteger, AtomicLong, AtomicReference等類,它們的基本特性就是在多線程環境下,執行這些類執行個體包含的方法時,具有排他性,即當某個線程進入方法,執行其中的指令時,不會被其他線程打斷,而别的線程就像自旋鎖一樣,一直等到該方法執行完成,才由JVM從等待隊列中選擇一個另一個線程進入。

舉例說明

以AtomicBoolean為例,單線程執行普通的方法(如下),不會出現線程問題:

1、單線程

package com.example.test;

/**
 * Created by PC on 2018/4/28.
 */

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();
    }
}
           

單線程結局

張三,step 
張三,step 
張三,step 
           

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

2、多線程

package com.example.test;

/**
 * Created by PC on 2018/4/28.
 */

public class NormalBoolean2 implements Runnable{


    private String name;

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

    @Override
    public void run() {
         //如果exit為false
        if(!TestBoolean.exits){
            try {
                Thread.sleep();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            TestBoolean.exits = true;

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

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


            System.out.println(name + ",step 3");
            TestBoolean.exits = false;

        } else {
            System.out.println(name + ",step else");
        }

    }
}
           

多線程啟動

package com.example.test;

/**
 * Created by PC on 2018/4/28.
 */

public class TestBoolean {
    public  static boolean exits = false;
    public static void main(String[] args) {
    //在這裡啟動的時候,啟動了4個線程,每一個線程啟動前睡眠1秒鐘,這樣的話一個線程跑得快,就可能出現變更exits的值,進而走到else語句裡。
     for(int i=;i<;i++){
             try {
                 Thread.sleep();
                 } catch (InterruptedException e) {
                 e.printStackTrace();
            }
       Thread thread = new Thread(new NormalBoolean2("李四"+i));
       thread.start();


        }
    }
}
           

多線程結局

線程0,跑得比較快,當他執行完TestBoolean.exits = true時,線程1正好走到 if(!TestBoolean.exits)的判斷。這時候,if裡面的判斷語句為!TestBoolean.exits=false,于是線程1走進了else語句。這證明了多線程執行是不安全的。

李四,step 
李四,step else
李四,step 
李四,step 
李四,step 
李四,step 
李四,step 
李四,step 
李四,step 
李四,step 
           

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

3、AtomicBoolean多線程

package com.example.test;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by PC on 2018/4/28.
 */

public class TestAtomicBoolean implements Runnable{

    //使用給定的初始值建立新的 AtomicBoolean。
    public static AtomicBoolean exits = new AtomicBoolean(false);
    private String name;

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

    @Override
    public void run() {
        //一般情況下,我們使用 AtomicBoolean 高效并發處理 “隻初始化一次” 的功能要求:
        //如果目前狀态值等于預期值,則以原子方式将同步狀态設定為給定的更新值。
        //如果成功,則傳回 true。傳回 False 訓示實際值與預期值不相等。
        //1.取得目前值
        //2.計算+1後的值
        //3.如果目前值還有效(沒有被别的線程修改的話),設定那個+1後的值
        //4.如果設定沒成功(目前值已經無效了即被别的線程改過了), 再從1開始.
        boolean curent=exits.get();//傳回目前值。
         System.out.println(curent);
        //compareAndSet(預期值, 新值)
        if(exits.compareAndSet(false,true)){
            System.out.println(name + ",step 1");
            System.out.println(name + ",step 2");
            System.out.println(name + ",step 3");
        } else {
            System.out.println(name + ",step else");
        }

    }
}
           

AtomicBoolean多線程啟動

package com.example.test;

/**
 * Created by PC on 2018/4/28.
 */

public class TestBoolean {
    public  static boolean exits = false;
    public static void main(String[] args) {

        for(int i=;i<;i++){
         try {
                Thread.sleep();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
      Thread thread = new Thread(new TestAtomicBoolean("張三"+i));
      thread.start();


       }
    }
}
           

AtomicBoolean多線程結局

線程0進來的時候,目前狀态值(false)等于預期值(false),于是走if語句,并将目前狀态值設定為給定的更新值(true)。從這以後,目前狀态值(true)不等于預期值(false),于是永遠走else()語句

false
張三,step 
張三,step 
張三,step 
true
張三,step else
true
張三,step else
true
張三,step else
true
張三,step else
true
張三,step else
true
張三,step else
true
張三,step else
true
張三,step else
true
張三,step else
           
注意:本文參考了https://blog.csdn.net/wo541075754/article/details/51509586,這篇部落格寫得很好,但是有很多問題,于是我呢修改了該部落格。