java多线程-原子类AtomicBoolean
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 并不没有按我们预期那样完成一个后而进入一个的方式处理业务,
atomicTest()方法的执行结果:当 worker1进入if内部后,worker2再尝试进入,结果是无法进入,
如下图,[1]标注处初始化赋值是false,当前执行到[2]标注处,此时会去判断标注[1]的值与标注[2]的值是否相等,
如果是相等,则将atomicWorking的值更新为标注[3]的值,并进入if内部执行业务,
如果不相等,则不能进入if内部,进入else内部
使用synchronized 公平锁的使用方式:此实现方式看其它博主的文章解释是无法达到线程安全的要求,但我测试了近20次都是可以,
源码:
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 方法示例
评论