【Java多线程】Java 原子操作类API(以AtomicInteger为例)
1、java.util.concurrent.atomic 的包里有AtomicBoolean, AtomicInteger,AtomicLong,AtomicLongArray,
AtomicReference等原子类的类,主要用于在高并发环境下的高效程序处理,来帮助我们简化同步处理.
在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。
2、AtomicInteger的基本方法
- 从AtomicInteger获取值
  System.out.println(atomicInteger.get());
--->输出 : 123
- 创建一个不传值的,默认值为0
  AtomicInteger atomicInteger = new AtomicInteger();
  System.out.println(atomicInteger.get());
---->输出: 0
- 获取和赋值
atomicInteger.get(); //获取当前值
atomicInteger.set(999); //设置当前值
- atomicInteger.compareAndSet(expectedValue,newValue)
 public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(0);
        System.out.println(atomicInteger.get());
        int expectedValue = 123;
        int newValue      = 234;
        Boolean b =atomicInteger.compareAndSet(expectedValue, newValue);
        System.out.println(b);
        System.out.println(atomicInteger);
    }
----》输出结果为: 0 false 0
 public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(123);
        System.out.println(atomicInteger.get());
        int expectedValue = 123;
        int newValue      = 234;
        Boolean b =atomicInteger.compareAndSet(expectedValue, newValue);
        System.out.println(b);
        System.out.println(atomicInteger);
    }
-----》输出结果为: 123 true  234
由上可知该方法表示,atomicInteger的值与expectedValue相比较,如果不相等,则返回false,
atomicInteger原有值保持不变;如果两者相等,则返回true,atomicInteger的值更新为newValue
- getAndAdd()方法与AddAndGet方法
       AtomicInteger atomicInteger = new AtomicInteger(123);
        System.out.println(atomicInteger.get());  --123
        System.out.println(atomicInteger.getAndAdd(10)); --123 获取当前值,并加10
        System.out.println(atomicInteger.get()); --133
        System.out.println(atomicInteger.addAndGet(10)); --143 获取加10后的值,先加10
        System.out.println(atomicInteger.get()); --143
- getAndDecrement()和DecrementAndGet()方法
        AtomicInteger atomicInteger = new AtomicInteger(123);
        System.out.println(atomicInteger.get());   --123
        System.out.println(atomicInteger.getAndDecrement()); --123 获取当前值并自减
        System.out.println(atomicInteger.get());  --122
        System.out.println(atomicInteger.decrementAndGet()); --121 先自减再获取减1后的值
        System.out.println(atomicInteger.get()); --121
3、使用AtomicInteger,即使不用同步块synchronized,最后的结果也是100,可用看出AtomicInteger的作用,用原子方式更新的int值。主要用于在高并发环境下的高效程序处理。使用非阻塞算法来实现并发控制。
public class Counter {
    public static AtomicInteger count = new AtomicInteger(0);
    public static void inc(){
        try{
            Thread.sleep(1); //延迟1毫秒
        }catch (InterruptedException e){ //catch住中断异常,防止程序中断
            e.printStackTrace();
        }
        count.getAndIncrement();//count值自加1
    }
    public static void main(String[] args) throws InterruptedException {
        final CountDownLatch latch = new CountDownLatch(100);
        for(int i=0;i<100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                    latch.countDown();
                }
            }).start();
        }
        latch.await();
        System.out.println("运行结果:"+Counter.count);
    }
}
运行结果: 100
4、使用普通Integer
public class Counter {
    public volatile  static int count = 0;
    public static void inc(){
        try{
            Thread.sleep(1); //延迟1毫秒
        }catch (InterruptedException e){ //catch住中断异常,防止程序中断
            e.printStackTrace();
        }
        count++;//count值自加1
    }
    public static void main(String[] args) throws InterruptedException {
        final CountDownLatch latch = new CountDownLatch(100);
        for(int i=0;i<100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                    latch.countDown();
                }
            }).start();
        }
        latch.await();
        System.out.println("运行结果:"+Counter.count);
   }
}
运行结果:98
5、如果在inc方法前面加个synchronized也能是线程安全的;
它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
import java.util.concurrent.CountDownLatch;
/**
 * created by guanguan  on 2017/10/23
 **/
public class Counter {
     public volatile static  Integer count = 0;
    public synchronized static void inc(){
        try{
            Thread.sleep(1); //延迟1毫秒
        }catch (InterruptedException e){ //catch住中断异常,防止程序中断
            e.printStackTrace();
        }
          count++;//count值自加1
    }
    public static void main(String[] args) throws InterruptedException {
        final CountDownLatch latch = new CountDownLatch(100);
        for(int i=0;i<100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                    latch.countDown();
                }
            }).start();
        }
        latch.await();
        System.out.println("运行结果:"+Counter.count);
    }
}
运行结果:100
synchronized的使用说明:
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用.
6、从上面的例子中我们可以看出:使用AtomicInteger是非常的安全的.而且因为AtomicInteger由硬件提供原子操作指令实现的。在非激烈竞争的情况下,开销更小,速度更快。
java的关键域有3个
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
private volatile int value;
这里, unsafe是java提供的获得对对象内存地址访问的类,注释已经清楚的写出了,它的作用就是在更新操作时提供“比较并替换”的作用。实际上就是AtomicInteger中的一个工具。
valueOffset是用来记录value本身在内存的便宜地址的,这个记录,也主要是为了在更新操作在内存中找到value的位置,方便比较。
注意:value是用来存储整数的时间变量,这里被声明为volatile,就是为了保证在更新操作时,当前线程可以拿到value最新的值(并发环境下,value可能已经被其他线程更新了)。
这里,我们以自增的代码为例,可以看到这个并发控制的核心算法:
源码
 public final int updateAndGet(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }
【Java多线程】Java 原子操作类API(以AtomicInteger为例)的更多相关文章
- Java多线程之原子操作类
		在并发编程中很容易出现并发安全问题,最简单的例子就是多线程更新变量i=1,多个线程执行i++操作,就有可能获取不到正确的值,而这个问题,最常用的方法是通过Synchronized进行控制来达到线程安全 ... 
- java中的原子操作类AtomicInteger及其实现原理
		/** * 一,AtomicInteger 是如何实现原子操作的呢? * * 我们先来看一下getAndIncrement的源代码: * public final int getAndIncremen ... 
- Java多线程并发工具类-信号量Semaphore对象讲解
		Java多线程并发工具类-Semaphore对象讲解 通过前面的学习,我们已经知道了Java多线程并发场景中使用比较多的两个工具类:做加法的CycliBarrier对象以及做减法的CountDownL ... 
- Java中的原子操作类
		转载: <ava并发编程的艺术>第7章 当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量i=1,A线程更新i+1,B线程也更新i+1,经过两个线程操作之后可 ... 
- Java并发之原子操作类汇总
		当程序更新一个变量时,如果是多线程同时更新这个变量,可能得到的结果与期望值不同.比如:有一个变量i,A线程执行i+1,B线程也执行i+1,经过两个线程的操作后,变量i的值可能不是期望的3,而是2.这是 ... 
- Java多线程01(Thread类、线程创建、线程池)
		Java多线程(Thread类.线程创建.线程池) 第一章 多线程 1.1 多线程介绍 1.1.1 基本概念 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于 ... 
- 【Java并发】Java中的原子操作类
		综述 JDK从1.5开始提供了java.util.concurrent.atomic包. 通过包中的原子操作类能够线程安全地更新一个变量. 包含4种类型的原子更新方式:基本类型.数组.引用.对象中字段 ... 
- Java多线程基础——Lock类
		之前已经说道,JVM提供了synchronized关键字来实现对变量的同步访问以及用wait和notify来实现线程间通信.在jdk1.5以后,JAVA提供了Lock类来实现和synchronized ... 
- Java多线程同步工具类之CountDownLatch
		在过去我们实现多线程同步的代码中,往往使用join().wait().notiyAll()等线程间通信的方式,随着JUC包的不断的完善,java为我们提供了丰富同步工具类,官方也鼓励我们使用工具类来实 ... 
- (转)java 多线程 对象锁&类锁
		转自:http://blog.csdn.net/u013142781/article/details/51697672 最近工作有用到一些多线程的东西,之前吧,有用到synchronized同步块,不 ... 
随机推荐
- Git 修改已提交的commit注释
			两种情况: 1.已经将代码push到远程仓库 2.还没将代码push到远程仓库,还在本地的仓库中 这两种情况下的修改大体相同,只是第一种情况最后会多一步 下面来说怎么修改 先搞清楚你要修改哪次的提交注 ... 
- python中jsonpath模块,解析多层嵌套的json数据
			1. jsonpath介绍用来解析多层嵌套的json数据;JsonPath 是一种信息抽取类库,是从JSON文档中抽取指定信息的工具,提供多种语言实现版本,包括:Javascript, Python, ... 
- 面试官:咱们来聊一聊mysql主从延迟
			背景 前段时间遇到一个线上问题,后来排查好久发现是因为主从同步延迟导致的,所以今天写一篇文章总结一下这个问题希望对你有用.如果觉得还不错,记得加个关注点个赞哦 思维导图 思维导图 常见的主从架构 随着 ... 
- Linux——搭建Samba(CIFS)服务器
			一.Samba的基本概念 Samba服务:是提供基于Linux和Windows的共享文件服务,服务端和客户端都可以是Linux或Windows操作系统.可以基于特定的用户访问,功能比NFS更强大. S ... 
- Prometheus的监控解决方案(含监控kubernetes)
			prometheus的简介和安装 Prometheus(普罗米修斯)是一个开源系统监控和警报工具,最初是在SoundCloud建立的.自2012年成立以来,许多公司和组织都采用了普罗米修斯,该项目拥有 ... 
- 力扣 - 剑指 Offer 22. 链表中倒数第k个节点
			题目 剑指 Offer 22. 链表中倒数第k个节点 思路1(栈) 既然要倒数第k个节点,那我们直接把所有节点放到栈(先进后出)里面,然后pop弹出k个元素就可以了 代码 class Solution ... 
- 微信公众号生成海报(uniapp)
			前言 这几天接到一个需求,要在公众号内生成分享海报.之前有做过H5和小程序的,心想直接复制过来就行了.没想到踩了不少的坑,搞了好几天终于搞好了,特此分享一下,希望能对大家有所帮助. 效果图 代码实现 ... 
- [loj2586]选圆圈
			下面先给出比较简单的KD树的做法-- 根据圆心建一棵KD树,然后模拟题目的过程,考虑搜索一个圆 剪枝:如果当前圆[与包含该子树内所有圆的最小矩形]都不相交就退出 然而这样的理论复杂度是$o(n^2)$ ... 
- [bzoj1146]网络管理
			发现是链上的问题,所以树链剖分发现要查询第k大,因为第k大不支持合并,所以要二分答案二分答案后相当于询问一些区间内大于某数的数个数,直接线段树套平衡树即可时间复杂度$o(nlog^{4}_n)$(跟$ ... 
- [atAGC046F]Forbidden Tournament
			称满足第1个条件的图为竞赛图,先来分析竞赛图 结论1:竞赛图点集上的导出子图也为竞赛图(证明略) 结论2:对于一张竞赛图,若不含有3元环,则该图为DAG 证明:反证法,若其不为DAG,设最小的简单环为 ... 
