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为例)的更多相关文章

  1. Java多线程之原子操作类

    在并发编程中很容易出现并发安全问题,最简单的例子就是多线程更新变量i=1,多个线程执行i++操作,就有可能获取不到正确的值,而这个问题,最常用的方法是通过Synchronized进行控制来达到线程安全 ...

  2. java中的原子操作类AtomicInteger及其实现原理

    /** * 一,AtomicInteger 是如何实现原子操作的呢? * * 我们先来看一下getAndIncrement的源代码: * public final int getAndIncremen ...

  3. Java多线程并发工具类-信号量Semaphore对象讲解

    Java多线程并发工具类-Semaphore对象讲解 通过前面的学习,我们已经知道了Java多线程并发场景中使用比较多的两个工具类:做加法的CycliBarrier对象以及做减法的CountDownL ...

  4. Java中的原子操作类

    转载: <ava并发编程的艺术>第7章 当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量i=1,A线程更新i+1,B线程也更新i+1,经过两个线程操作之后可 ...

  5. Java并发之原子操作类汇总

    当程序更新一个变量时,如果是多线程同时更新这个变量,可能得到的结果与期望值不同.比如:有一个变量i,A线程执行i+1,B线程也执行i+1,经过两个线程的操作后,变量i的值可能不是期望的3,而是2.这是 ...

  6. Java多线程01(Thread类、线程创建、线程池)

    Java多线程(Thread类.线程创建.线程池) 第一章 多线程 1.1 多线程介绍 1.1.1 基本概念 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于 ...

  7. 【Java并发】Java中的原子操作类

    综述 JDK从1.5开始提供了java.util.concurrent.atomic包. 通过包中的原子操作类能够线程安全地更新一个变量. 包含4种类型的原子更新方式:基本类型.数组.引用.对象中字段 ...

  8. Java多线程基础——Lock类

    之前已经说道,JVM提供了synchronized关键字来实现对变量的同步访问以及用wait和notify来实现线程间通信.在jdk1.5以后,JAVA提供了Lock类来实现和synchronized ...

  9. Java多线程同步工具类之CountDownLatch

    在过去我们实现多线程同步的代码中,往往使用join().wait().notiyAll()等线程间通信的方式,随着JUC包的不断的完善,java为我们提供了丰富同步工具类,官方也鼓励我们使用工具类来实 ...

  10. (转)java 多线程 对象锁&类锁

    转自:http://blog.csdn.net/u013142781/article/details/51697672 最近工作有用到一些多线程的东西,之前吧,有用到synchronized同步块,不 ...

随机推荐

  1. vs Code配置C++运行和调试环境以及相关问题

    vs Code配置C++运行和调试环境以及相关问题 第一步:下载c++插件 第二步:安装编译.调试环境 如果没有Dev-C++下载MinGW 下载地址:https://sourceforge.net/ ...

  2. BootStrap_1 浓缩版本

    BootStrap(基于JQuery框架) 商业互吹:Bootstrap是最受欢迎的HTML.CSS和JS框架,用于开发响应式布局,移动设备优先选择的WEB项目... 特色:1.响应式布局 2.基于f ...

  3. stop services in init

    echo 'manual' | sudo tee /etc/init/mysql.override # command from root shellecho manual >> /etc ...

  4. React-Router学习(基础路由与嵌套路由)

    示例:基本路由 在这个例子中,我们有3个'Page'组件处理<Router>. 注意:而不是<a href="/">我们使用<Link to=&quo ...

  5. 【JavaScript使用技巧】三个截取字符串中的子串,你用的哪个

    [JavaScript使用技巧]三个截取字符串中的子串,你用的哪个 博客说明 文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢! slice( ...

  6. element ui tree回显 setCheckedNodes,setCheckedKeys,setChecked等函数报undefined问题

    在写项目的时候,需要用到tree组件进行回显来进行权限控制: 在回显过程中使用回显函数会报报undefined, 这时只需要给该函数包裹一层nextTick方法就行了, 在回显过程中我们有可能使用半选 ...

  7. 手把手教你学Dapr - 9. 可观测性

    目录 手把手教你学Dapr - 1. .Net开发者的大时代 手把手教你学Dapr - 2. 必须知道的概念 手把手教你学Dapr - 3. 使用Dapr运行第一个.Net程序 手把手教你学Dapr ...

  8. Docker Compose 容器编排 NET Core 6+MySQL 8+Nginx + Redis

    环境: CentOS 8.5.2111Docker 20.10.10Docker-Compose 2.1.0 服务: db  redis  web nginx NET Core 6+MySQL 8+N ...

  9. 七、Hadoop3.3.1 HA 高可用集群QJM (基于Zookeeper,NameNode高可用+Yarn高可用)

    目录 前文 Hadoop3.3.1 HA 高可用集群的搭建 QJM 的 NameNode HA Hadoop HA模式搭建(高可用) 1.集群规划 2.Zookeeper集群搭建: 3.修改Hadoo ...

  10. Vue3学习与实战 · 全局挂载使用Axios

    在vue2中会习惯性的把axios挂载到全局,以方便在各个组件或页面中使用this.$http请求接口.但是在vue3中取消了Vue.prototype,在全局挂载方法和属性时,需要使用官方提供的gl ...