java中Atomic类之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 1
张三,step 2
张三,step 3

然而,当多线程执行时,就会出现在执行判断之后的命令时,会有其他线程插入,变更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(1000);
            } 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=0;i<4;i++){
             try {
                 Thread.sleep(1000);
                 } 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语句。这证明了多线程执行是不安全的。

李四0,step 1
李四1,step else
李四0,step 2
李四0,step 3
李四2,step 1
李四2,step 2
李四2,step 3
李四3,step 1
李四3,step 2
李四3,step 3

现在,使用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=0;i<10;i++){
         try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
      Thread thread = new Thread(new TestAtomicBoolean("张三"+i));
      thread.start();


       }
    }
}

AtomicBoolean多线程结局

线程0进来的时候,当前状态值(false)等于预期值(false),于是走if语句,并将当前状态值设置为给定的更新值(true)。从这以后,当前状态值(true)不等于预期值(false),于是永远走else()语句

false
张三0,step 1
张三0,step 2
张三0,step 3
true
张三1,step else
true
张三2,step else
true
张三3,step else
true
张三4,step else
true
张三5,step else
true
张三6,step else
true
张三7,step else
true
张三8,step else
true
张三9,step else

注意:本文参考了https://blog.csdn.net/wo541075754/article/details/51509586,这篇博客写得很好,但是有很多问题,于是我呢修改了该博客。


你可能感兴趣的:(java)