并发编程之无锁

2020-02-16  本文已影响0人  小小一技术驿站

@TOC

6.2 CAS与volatile

在这里插入图片描述
其中的关键是compareAndSet,它的简称就是CAS(也有Compare And Swap的说法),它必须是原子操作。
在这里插入图片描述
注意
其实CAS的底层是lock cmpxchg指令(X86架构),在单核CPU和多核CPU下都能够保证【比较-交换】的原子性。
package com.example.demo;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class Test4 {
    public static void main(String[] args) {
        demo(
                () -> new AtomicLong(0),
                (adder) -> adder.getAndIncrement()
        );
        
        demo(
                () -> new LongAdder(),
                (adder) -> adder.increment()
        );
    }

    /**
     *
     * @param adderSupplier : () -> 结果   提供累加器对象
     * @param action        : (参数) -> void  执行累加操作
     * @param <T>
     */
    private static <T> void demo(Supplier<T> adderSupplier, Consumer<T> action) {
        T adder = adderSupplier.get();
        List<Thread> threadList = new ArrayList<>();
        // 4个线程,每人累加50万
        for (int i = 0; i < 4; i++) {
            threadList.add(new Thread(() -> {
                for (int j = 0; j < 500000; j++) {
                    action.accept(adder);
                }
            }));
        }
        long start = System.nanoTime();
        threadList.forEach(t -> t.start());
        long end = System.nanoTime();
        System.out.println(adder + " cost : " + (end - start));
    }
}
package com.example.demo;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class Test3 {

    public static void main(String[] args) {

    }

    /**
     * 参数1,提供数组,可以是线程不安全数组或线程安全数组
     * 参数2,获取数组长度的方法
     * 参数3,自增方法,回传array,index
     * 参数4,打印数组的方法
     *
     * @param arraySupplier : 提供者  无中生有  () -> 结果
     * @param lengthFun    : 函数    一个参数一个结果  (参数) -> 结果 ,BiFunction(参数1,参数2) -> 结果
     * @param putConsumer  : 消费者  (参数1,参数2) -> void
     * @param printConsumer : 消费者  (参数) -> void
     * @param <T>
     */
    private static <T> void demo(
            Supplier<T> arraySupplier,
            Function<T, Integer> lengthFun,
            BiConsumer<T, Integer> putConsumer,
            Consumer<T> printConsumer
    ) {
        List<Thread> threadList = new ArrayList<>();
        T array = arraySupplier.get();
        Integer length = lengthFun.apply(array);
        for (int i = 0; i < length; i++) {
            // 每个线程对数组做10000次操作
            threadList.add(new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    putConsumer.accept(array, j % length);
                }
            }));
        }
        threadList.forEach(thread -> thread.start());
    }

}

输出


在这里插入图片描述

性能提升的原因很简单,就是在有竞争时,设置多个累加单元,Thread-0累加 Cel【0】,而Thread-1累加Cell【1】。。。最后将结果汇总。这样它们在累加时操作的不同的Cell变量,因此减少了CAS重试失败,从而提高性能。

源码之LongAdder

LongAdder类有几个关键域


在这里插入图片描述

6.8 Unsafe

概述
Unsafe对象提供了非常底层的,操作内存、线程的方法,Unsafe对象不能直接调用,只能通过反射获得

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上一篇下一篇

猜你喜欢

热点阅读