java多线程-原子类AtomicBoolean

sancaiodm Java 2021-09-30 1374 0

      JDK1.5之后的java.util.concurrent.atomic包里多了一批原子处理类。AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference。他们主要用于在高并发环境下的高效程序处理,来帮助我们简化同步处理。当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当A某个线程进入方法执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入,

    

     本篇要讲的主角是:AtomicBoolean,AtomicBoolean其实也就是一个boolean值,只是它是原子操作,是线程安全的。而我们常用的boolean是非线程安全的,非线程安全的操作在多线程操作时会给我们造成各种问题,所以在要求线程安全操作下的boolean类型的线程安全类AtomicBoolean就应运而生了,

    在这个Boolean值的变化的时候不允许在它变化时插入其它指令 (通俗的话就是 AtomicBoolean 变量值改变之际不允许插入执行其它业务),保持操作的原子性

    AtomicBoolean内compareAndSet(boolean expect, boolean update)  这个方法主的作用是:

         比较AtomicBoolean当前值和expect的值,如果一致,则将update的值赋值给AtomicBoolean,并执行if判断内的业务。

        且这两件事是一并执行的,是一气呵成的,这两个动作之间不会被打断,任何内部或者外部的语句都不可能在两个动作之间运行。为多线程的控制提供了解决的方案。


示例:需求是要实现同一时间只能是一个worker工作者在工作,当有worker在工作时,则其它 worker需要等待(进入堵塞状态),直至之前的worker完成工作,其它worker才可以进入工作

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class AtomicBooleanTest implements Runnable {
	 private static boolean isworking = false;  
	 private String mWorkerName;  
	 public AtomicBooleanTest(String name) {   
		  this.mWorkerName = name;  
    }  
	 
	 @Override  
	 public void run() {   
		 normalTest();
		 //atomicTest();
		 //test();
   } 
	 public static void main(String[] args) {
		 AtomicBooleanTest worker1 = new AtomicBooleanTest("worker1");
		 AtomicBooleanTest worker2 = new AtomicBooleanTest("worker2");
		 new Thread(worker1).start();
		 new Thread(worker2).start();
	}
	 
	 private void normalTest() {
		 if (!isworking) {
		     System.out.println(mWorkerName + " enter"+" do somethings....");   
		     isworking = true;   
		     try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} 
		     System.out.println(mWorkerName + " ready to leave"); 
		     isworking = false;  
	    } else {  
	         System.out.println(mWorkerName + " other people is do somethings ,One moment please");  
	    } 
	 }
	 
	 private static AtomicBoolean atomicWorking = new AtomicBoolean(false); 
	 private void atomicTest() {
		 if(atomicWorking.compareAndSet(false, true)) {
			 System.out.println(mWorkerName + " enter"+" do somethings....");   
		     try {
				 TimeUnit.SECONDS.sleep(1);
			 } catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
			 } 
		     System.out.println(mWorkerName + " ready to leave"); 
		     atomicWorking.set(false);
		} else {  
		     System.out.println(mWorkerName + " other people is do somethings ,One moment please");  
		} 
	 }
	 
	 private  Boolean flag = false;
	 public void test() {
	   synchronized(flag) {
		   if(!flag) {
			   System.out.println("goin  mWorkName = "+mWorkerName);
			   flag = true;
				 try {
						TimeUnit.SECONDS.sleep(5);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} 
			     System.out.println("out  mWorkName = "+mWorkerName);
			     flag = true;
			}
		}
	 }
}

normalTest() 方法的执行结果: 很显然woker1 与worker2 并不没有按我们预期那样完成一个后而进入一个的方式处理业务,

image.png

atomicTest()方法的执行结果:当 worker1进入if内部后,worker2再尝试进入,结果是无法进入,

如下图,[1]标注处初始化赋值是false,当前执行到[2]标注处,此时会去判断标注[1]的值与标注[2]的值是否相等,

如果是相等,则将atomicWorking的值更新为标注[3]的值,并进入if内部执行业务,

如果不相等,则不能进入if内部,进入else内部

image.png

使用synchronized 公平锁的使用方式:此实现方式看其它博主的文章解释是无法达到线程安全的要求,但我测试了近20次都是可以,

image.png




源码:

    public final void set(boolean newValue) {    //设置新值
        value = newValue ? 1 : 0;
    }

    /**
     * Returns the current value,
     * with memory effects as specified by {@link VarHandle#getVolatile}.
     *
     * @return the current value
     */
    public final boolean get() {   //返回当前值
        return value != 0;
    }

    /**
     * Atomically sets the value to {@code newValue} and returns the old value,
     * with memory effects as specified by {@link VarHandle#getAndSet}.
     *
     * @param newValue the new value
     * @return the previous value
     */
    public final boolean getAndSet(boolean newValue) {    //设置一个新值并返回旧值
        return (int)VALUE.getAndSet(this, (newValue ? 1 : 0)) != 0;
    }

getAndSet 方法示例

image.png

评论