当多个线程访问同一个类时,无论运行时环境采用何种调度方式,不论线程如何交替执行,在主调代码中不须要额外的协同或者同步代码时,这个类均可以表现出正确的行为,咱们则称这个类为线程安全的。
(关于什么是主内存什么事工做内存在上篇博客中进行介绍了,不懂的同窗能够翻一下)示例代码:java
@Slf4j public class AtomicExample2 { // 请求总数 public static int clientTotal = 5000; // 同时并发执行的线程数 public static int threadTotal = 200; public static AtomicLong count = new AtomicLong(0); public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadTotal); final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal ; i++) { executorService.execute(() -> { try { semaphore.acquire(); add(); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("count:{}", count.get()); } private static void add() { count.incrementAndGet(); // count.getAndIncrement(); } }
jdk8中新增的保证同步操做的类,咱们以前介绍了AtomicXXX来保证原子性,那么为何还有有LongAdder呢?
说AtomicXXX的实现是经过死循环来判断值的,在低并发的状况下AtomicXXX进行更改值的命中率仍是很高的。可是在高并发下进行命中率可能没有那么高,从而一直执行循环操做,此时存在必定的性能消耗,在jvm中咱们容许将64位的数值拆分红2个32位的数进行储存的,LongAdder的思想就是将热点数据分离,将AtomicXXX中的核心数据分离,热点数据会被分离成多个数组,每一个数据都单独维护各自的值,将单点的并行压力发散到了各个节点,这样就提升了并行,在低并发的时候性能基本和AtomicXXX相同,在高并发时具备较好的性能,缺点是在并发更新时统计时可能会出现偏差。在低并发,须要全局惟一,准确的好比id等使用AtomicXXX,要求性能使用LongAdder数组
@Slf4j public class AtomicExample3 { // 请求总数 public static int clientTotal = 5000; // 同时并发执行的线程数 public static int threadTotal = 200; public static LongAdder count = new LongAdder(); public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadTotal); final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);、】【poiuytrewq;' for (int i = 0; i < clientTotal ; i++) { executorService.execute(() -> { try { semaphore.acquire(); add(); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("count:{}", count); } private static void add() { count.increment(); } }
@Slf4j public class AtomicExample4 { private static AtomicReference<Integer> count = new AtomicReference<>(0); public static void main(String[] args) { count.compareAndSet(0, 2); // 2 count.compareAndSet(0, 1); // no count.compareAndSet(1, 3); // no count.compareAndSet(2, 4); // 4 count.compareAndSet(3, 5); // no log.info("count:{}", count.get()); } }
AtomMNBVCXZenceFieldUpdater主要是更新某一个实例对象的一个字段这个字段必须是用volatile修饰同时不能是private修饰的,·157-=· 123444457890-
@Slf4j public class AtomicExample5 { private static AtomicIntegerFieldUpdater<AtomicExample5> updater = AtomicIntegerFieldUpdater.newUpdater(AtomicExample5.class, "count"); @Getter public volatile int count = 100; public static void main(String[] args) { AtomicExample5 example5 = new AtomicExample5(); if (updater.compareAndSet(example5, 100, 120)) { log.info("update success 1, {}", example5.getCount()); } if (updater.compareAndSet(example5, 100, 120)) { log.info("update success 2, {}", example5.getCount()); } else { log.info("update failed, {}", example5.getCount()); } } }
最后咱们介绍一下使用AtomicBoolean来实现只执行一次的操做,咱们使用private static AtomicBoolean isHappened = new AtomicBoolean(false)来初始化一个具备原子性的一个Boolean的记录是否已经被执行安全
@Slf4j public class AtomicExample6 { private static AtomicBoolean isHappened = new AtomicBoolean(false); // 请求总数 public static int clientTotal = 5000; // 同时并发执行的线程数 public static int threadTotal = 200; public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadTotal); final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal ; i++) { executorService.execute(() -> { try { semaphore.acquire(); test(); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("isHappened:{}", isHappened.get()); } private static void test() { if (isHappened.compareAndSet(false, true)) { log.info("execute"); } } }
咱们除了可使用Atomic包还可使用锁来实现。