[High] -java concurrent thematic thread safety - atomic -Automic kits Comments

Thread safety

When multiple threads access a class, no matter what kind of thread scheduling approach taken in the calling code does not need to take additional synchronization or coordination, this class can show the correct behavior, then this class is thread-safe .

Three properties thread-safe

Atomic: provides exclusive access, only one thread at a time to operate it.

Visibility: Modifying a thread of main memory will be seen by other threads.

Ordering: compilers and processors may order the performance of the operating instruction reorder, re-ordering execution will not affect the single thread program, but the program multiple threads of execution but will be affected.

Case simulation thread safe:

//模拟线程不安全
public class AtomicTest1 {
    private static final int clientTotal = 5000;
    private static final int threadTotal = 200;
    private static int count = 0;

    public static void main(String[] args) throws Exception {
        ExecutorService es = Executors.newCachedThreadPool();
        final CountDownLatch ctl = new CountDownLatch(clientTotal);
        final Semaphore semaphore = new Semaphore(threadTotal);
        for (int i = 0; i < clientTotal; i++) {
            es.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                ctl.countDown();
            });
        }
        ctl.await();
        es.shutdown();
        System.out.println("count:" + count);
    }

    public static void add() {
        count++;
    }
}

Several operating results:

  

Apparently there was a thread-unsafe.

We can use the class provided under java.util.current.atomic package to solve

//模拟线程安全
public class AtomicTest2 {
    private static final int clientTotal = 5000;
    private static final int threadTotal = 200;
    private static AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) throws Exception {
        ExecutorService es = Executors.newCachedThreadPool();
        final CountDownLatch ctl = new CountDownLatch(clientTotal);
        final Semaphore semaphore = new Semaphore(threadTotal);
        for (int i = 0; i < clientTotal; i++) {
            es.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                ctl.countDown();
            });
        }
        ctl.await();
        es.shutdown();
        System.out.println("count:" + count);
    }

    public static void add() {
        count.getAndIncrement();
    }
}

After several execution, the result is still correct:

Which achieve getAndIncrement method, called unsafe method in sun.misc.unsafe package

compareAndSwap, this is what we are familiar with CAS spin lock in Jdk1.8 concurrentHashMap is also useful to it.

CAS referred to the way the ABA problem in the CAS, ABA that is a thread in the value of A is changed to B, B to another thread has changed back to the A, A value found during the operation and returned again a thread not changed, but in fact the value of a is to be manipulated, in this case in order to avoid failure .atomic CAS lock package provides classes AtomicStampReference ABA to solve the problem, the operation of each change of value, such will be the version number changed, so you can avoid the ABA problem.

Incidentally, similar AtomicLong, AtomicLong role and AtomicInteger, but not the same type of data, the reason for mentioning AtomicLong to elicit LongAdder newly provided jdk8, their function is similar, but there are differences in performance in the above code, we can see, getAndAdd method using a do while loop calls cas achieved, which in concurrent relatively high, the cycle takes more performance, so LongAdder its improved read and write operations will be digital by a similar hash algorithm into different cell, the cell finally accumulated value of the calculation results in a highly concurrent scenario, the dispersion performance gains will be apparent, however, to pay the price and therefore a loss of precision, the result of accumulation a slight error may occur.

JUC atomic packages under provides many classes can guarantee the atomicity, which is commonly used as shown:

Comparative expected value and the updated value fields AtomicReference:

public class AtomicTest4 {
    public static void main(String[] args) {
        AtomicReference<Integer> atomicReference = new AtomicReference<>(1);
        atomicReference.compareAndSet(1,2);
        atomicReference.compareAndSet(2,4);
        atomicReference.compareAndSet(3,5);
        atomicReference.compareAndSet(4,6);
        System.out.println(atomicReference.get());
    }
}

result:

AtomicXXXFieldUpdater implemented by a class corresponding to the type specified in fields volatile atomicity operations.

public class AtomicTest5 {
    @Getter
    public volatile int count = 100;
    private static AtomicTest5 atomicTest5 = new AtomicTest5();
    private static AtomicIntegerFieldUpdater<AtomicTest5> updater = AtomicIntegerFieldUpdater.newUpdater(AtomicTest5.class, "count");
    public static void main(String[] args) {
        if (updater.compareAndSet(atomicTest5,100,200)){
            System.out.println("success::"+atomicTest5.getCount());
        }else if (updater.compareAndSet(atomicTest5,500,800)){
            System.out.println("success::"+atomicTest5.getCount());
        }else {
            System.out.println("fail:"+atomicTest5.getCount());
        }
    }
}

result:

Use AtomicBoolean to ensure that a piece of code / method is executed only once:

public class AutomicTest6 {
    private static final int clientTotal = 5000;
    private static final int threadTotal = 2000;
    private static AtomicBoolean isHappend = new AtomicBoolean(false);

    public static void main(String[] args) throws Exception {
        ExecutorService es = Executors.newCachedThreadPool();
        final CountDownLatch ctl = new CountDownLatch(clientTotal);
        final Semaphore semaphore = new Semaphore(threadTotal);
        for (int i = 0; i < clientTotal; i++) {
            es.execute(() -> {
                try {
                    semaphore.acquire();
                    test();
                    semaphore.release();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                ctl.countDown();
            });
        }
        ctl.await();
        es.shutdown();
    }

    private static void test() {
        if (isHappend.compareAndSet(false, true)) {
            System.out.println("executed");
        }
    }
}

result:

AtomicIntegerArray, Int is an equivalent array, but the elements of atomic update is available.

public class AtomicTest7 {
    public static void main(String[] args) {
        AtomicIntegerArray array = new AtomicIntegerArray(10);
        array.set(5,50);
        ExecutorService es = Executors.newCachedThreadPool();
        for (int i = 0; i < 50; i++) {
            es.execute(()->{
                array.compareAndSet(5,50,80);
            });
        }
        es.shutdown();
        System.out.println(array.get(5));
    }
}

result: 

About atomic package to share here, interested can read Jdk1.8-api, api + turning point source appropriate reading for a better understanding very helpful, thanks for reading and finally, the paper if not correct place or have better suggestions also hope you spectators wing.

Published 89 original articles · won praise 70 · views 40000 +

Guess you like

Origin blog.csdn.net/lovexiaotaozi/article/details/90751466