i++的原子性问题-编程思维

i++的原子性问题

一、什么是原子性

  简单的可以理解为:操作是不可再分割的,比如;

int i=0;

但是i++的操作是可以再分的,比如:

i++ 
//分解后
i=i+i

上面的代码在多线程环境下取值是有问题的,比如:

package com.example.demo.juc;

/**
 * @author DUCHONG
 * @since 2019-01-07 19:11
 **/
public class AtomicTest {

    public static void main(String[] args) {

        AtomicThread atomicTest=new AtomicThread();
        for (int i=1;i<=20;i++){

            new Thread(atomicTest).start();
        }
    }
}

class AtomicThread implements Runnable {

    private  int num=1;
    @Override
    public void run() {
        try {
            Thread.sleep(300);
            System.out.println(getNum());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public int getNum(){
        return num++;
    }
}

结果:

这种问题当然可以通过加synchronized 关键字来解决,那有没有另外一种方案呢,答案肯定是有的,且在jdk1.5的时候就有了,那就是Atomic包下的原子类

优化后:

package com.example.demo.juc;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author DUCHONG
 * @since 2019-01-07 19:11
 **/
public class AtomicTest {

    public static void main(String[] args) {

        AtomicThread atomicTest=new AtomicThread();
        for (int i=1;i<=20;i++){

            new Thread(atomicTest).start();
        }
    }
}

class AtomicThread implements Runnable {

    private AtomicInteger at=new AtomicInteger(1);
    @Override
    public void run() {
        try {
            Thread.sleep(300);
            System.out.println(getNum());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public int getNum(){
        return at.getAndIncrement();
    }
}

看源码:

构造函数中的值,是volatile类型的

自增或者自减时,使用了CAS算法,CAS算法有三个操作数:

内存值:A

预估值:B

新值:V 

当且仅当 A=B 是 A=V 

否则不做任何操作。

版权声明:本文版权归作者所有转载请注明原文链接
https://www.cnblogs.com/geekdc/p/10235283.html

利用同步辅助类CountDownLatch计算多线程的运行时间-编程思维

一、CountDownLatch   jdk提供的一个同步辅助类,在完成一组在在其他线程中执行的操作前,允许一个或者多个其他的线程等待,通过调用 await() 方法阻塞,直到由于 countDown() 方法的调用而导致当前计数达到零,之后所有等待线程被释放。 二、计算多个线程执行时间 package com.ex

利用Condition实现多线程交替执行-编程思维

一、需求 A、B、C 三个线程,循环10次,打印出自己的名称,ABC,ABC,ABC... A、B、C 三个线程,循环10次,打印出自己的名称,A一次,B三次,C五次,ABBBCCCCC,ABBBCCCCC 1.1、循环打印ABC package com.example.demo.juc; import jav

ThreadLocal原理-编程思维

一、Thread public class Thread(){ //省略部分 //属于这个线程的ThreadLocals,这个map由ThreadLocal类维护 ThreadLocal.ThreadLocalMap threadLocals = null; //省