volatile关键字和AtomicInteger

在Java中,线程部分是一个重点,本篇文章说的JUC也是关于线程的。JUC就是java.util .concurrent工具包的简称。这是一个处理线程的工具包,JDK 1.5开始出现的。下面一起来看看它怎么使用。

一、volatile关键字与内存可见性

1、内存可见性:
先来看看下面的一段代码:

 

 

 

 

 

上图中这段代码很简单,就是一个ThreadDemo类继承Runnable创建一个线程。它有一个成员变量flag为false,然后重写run方法,在run方法里面将flag改为true,同时还有一条输出语句。然后就是main方法主线程去读取flag。如果flag为true,就会break掉while循环,否则就是死循环。按道理,下面那个线程将flag改为true了,主线程读取到的应该也是true,循环应该会结束。运行结果

 

从上图中可以看到,该程序并没有结束,也就是死循环。说明主线程读取到的flag还是false,可是另一个线程明明将flag改为true了,而且打印出来了,这是什么原因呢?这就是内存可见性问题。

  • 内存可见性问题:当多个线程操作共享数据时,彼此不可见。



要解决这个问题,可以加锁。如下:

加了锁,就可以让while循环每次都从主存中去读取数据,这样就能读取到true了。但是一加锁,每次只能有一个线程访问,当一个线程持有锁时,其他的就会阻塞,效率就非常低了。不想加锁,又要解决内存可见性问题,那么就可以使用volatile关键字。

 

2、volatile关键字:

  • 用法:

volatile关键字:当多个线程操作共享数据时,可以保证内存中的数据可见。用这个关键字修饰共享数据,就会及时的把线程缓存中的数据刷新到主存中去,也可以理解为,就是直接操作主存中的数据。所以在不使用锁的情况下,可以使用volatile。如下:


这样就可以解决内存可见性问题了。

  • volatile和synchronized的区别:
    volatile不具备互斥性(当一个线程持有锁时,其他线程进不来,这就是互斥性)。
    volatile不具备原子性。

 

 

二、原子性

1、理解原子性:
上面说到volatile不具备原子性,那么原子性到底是什么呢?先看如下代码:

 

 

这段代码就是在run方法里面让i++,然后启动十个线程去访问。看看结果:

 

 

可以发现,出现了重复数据。明显产生了多线程安全问题,或者说原子性问题。所谓原子性就是操作不可再细分,而i++操作分为读改写三步,如下:

 

所以i++明显不是原子操作。上面10个线程进行i++时,内存图解如下:

 

看到这里,好像和上面的内存可见性问题一样。是不是加个volatile关键字就可以了呢?其实不是的,因为加了volatile,只是相当于所有线程都是在主存中操作数据而已,但是不具备互斥性。比如两个线程同时读取主存中的0,然后又同时自增,同时写入主存,结果还是会出现重复数据。

2、原子变量:
JDK 1.5之后,Java提供了原子变量,在java.util.concurrent.atomic包下。原子变量具备如下特点:

  • 有volatile保证内存可见性。
  • 用CAS算法保证原子性。

3、CAS算法:
CAS算法是计算机硬件对并发操作共享数据的支持,CAS包含3个操作数:

  • 内存值V
  • 预估值A
  • 更新值B

当且仅当V==B时,才会把B的值赋给V,即V = B,否则不做任何操作。就上面的i++问题,CAS算法是这样处理的:首先V是主存中的值0,然后预估值A也是0,因为此时还没有任何操作,这时V=B,所以进行自增,同时把主存中的值变为1。如果第二个线程读取到主存中的还是0也没关系,因为此时预估值已经变成1,V不等于B,所以不进行任何操作。

4、使用原子变量改进i++问题:

 

  • 定义:AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减。
  • 使用场景 :适合高并发情况下的使用

    AtomicInteger是在使用非阻塞算法实现并发控制,在一些高并发程序中非常适合,但并不能每一种场景都适合,不同场景要使用使用不同的数值类。

    注意:高并发的情况下,i++无法保证原子性,往往会出现问题,所以引入AtomicInteger


原子变量用法和包装类差不多,如下:

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/271831.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端:JS几种常见的排序

❤️作者主页:IT技术分享社区 ❤️作者简介:大家好,我是IT技术分享社区的博主,从事C#、Java开发九年,对数据库、C#、Java、前端、运维、电脑技巧等经验丰富。 ❤️个人荣誉: 数据库领域优质创作者🏆&#x…

bzoj3747 [POI2015]Kinoman

线段树&#xff0c;记录next[i]下一部与当前电影一样的位置&#xff0c;然后枚举区间左端点i&#xff0c;询问线段树最大值后删除i到next[i-1]这段区间的观影值&#xff0c;且增加next[i]到next[next[i]]-1这段区间的观影值。 代码&#xff0c;跑的有点慢 1 #include<cstdio…

java_poi教程.pdf,如何使用POI转换.DOC / .DOCX为PDF在Java ..?

how to convert ms-document to PDF, is there any example pls sharewith me.. thanks.解决方案If you are requiered to use POI i guess you should take a look at org.apache.poi.hwpf.converterI never tried this, but i guess its worth a try atleast.It seems like y…

在线语音转文字工具V1.0

在线语音转文字工具V1.0介绍在线语音转文字工具V1.0&#xff0c;采用C#开发语音基于Framework4.5开发&#xff0c;主要采用百度语音识别SDK&#xff0c;实现了在线文本转语音的功能&#xff0c;可以转换后直接播放。有需要的朋友可以下载学习一下。如果遇到问题的可以留言或者私…

超媒体

“超媒体”是超级媒体的缩写。超媒体是一种采用非线性网状结构对块状多媒体信息&#xff08;包括文本、图像、视频等&#xff09;进行组织和管理的技术。 超媒体在本质上和超文本是一样的&#xff0c;只不过超文本技术在诞生的初期管理的对象是纯文本&#xff0c;所以叫做超文本…

java局部刷新session过期_Ajax局部页面刷新和History API结合的陷阱

ajax在现代网站已经得到非常普遍地应用&#xff0c;主要的好处大家都知道(异步加载数据&#xff0c;不用刷新整个浏览器&#xff0c;更小的数据传输尺寸)。对于那些老网站或者老项目来说全盘改造成ajax并不现实&#xff0c;于是就有了“局部页面刷新”这个解决方案。如果不知道…

Java通过Netty,实现Websocket消息推送只需要简单几步

前言 曾几何时&#xff0c;不知道大家有没有在项目里遇到过需要服务端给客户端推送消息的需求&#xff0c;是否曾经苦恼过、纠结过&#xff0c;我们知道要想实现这样的需求肯定离不开websocket长连接方式&#xff0c;那么到底是该选原生的websocket还是更加高级的netty框架呢&a…

53.Maximum Subarray

/** 53.Maximum Subarray * 2016-5-7 by Mingyang * 如果我们从头遍历这个数组。对于数组中的其中一个元素&#xff0c;它只有两个选择&#xff1a; 1.* 要么加入之前的数组加和之中&#xff08;跟别人一组&#xff09; * 2. 要么自己单立一个数组&#xff08;自己单开一组&…

java 创建者设计模式_Java设计模式之创建者模式分享热爱编程,程序人生

PS:今天的23中设计模式中的创建者方式&#xff0c;至此告一段落。我今天带来的技术分享为创建者模式以及原型模式。当然在Java中这两种方式很常见&#xff0c;只不过我们写的次数确实有点低而已&#xff0c;但是这不是我不学它的借口&#xff01;&#xff01;&#xff01;创建者…

一文读懂电感器的原理、结构、作用及分类

电感器是能够把电能转化为磁能而存储起来的元件。电感器的结构类似于变压器&#xff0c;但只有一个绕组。电感器具有一定的电感&#xff0c;它只阻碍电流的变化。 如果电感器在没有电流通过的状态下&#xff0c;电路接通时它将试图阻碍电流流过它&#xff1b;如果电感器在有电流…

final关键字与static对比

final关键字与static对比 static关键字修饰变量时&#xff0c;会使该变量在类加载时就会被初始化&#xff0c;不会因为对象的创建再次被加载&#xff0c;当变量被static 修饰时就代表该变量只会被初始化一次 例如图中所示&#xff0c;被static修饰的变量j&#xff0c;虽然创建…

juce中的BailOutChecker

界面库中值得注意的一点就是对象响应事件的时候自身被删除了&#xff0c;那么后续的访问自然就会出问题&#xff0c;所以需要在响应事件之后先添加引用&#xff0c;相关处理之后再查看自身是否已经被删除&#xff0c;如果已经被删除那么就直接退出。juce中通过BailOutChecker来…

java quartz 跳过_Java Quartz计划作业-禁止同时执行作业

我正在使用Quartz Job执行特定任务。我也在我的Main应用程序类中安排它的执行&#xff0c;而我试图完成的工作是不允许同时执行此作业的实例。因此&#xff0c;调度程序仅应在其先前实例完成后才执行作业。这是我的工作班级&#xff1a;public class MainJob implements Job {s…

mac USB串口工具配置

安装USB serial 驱动 我的usb serial芯片是 pl2303, 先到官网上下载对应驱动&#xff0c;并安装。安装完成之后会要求重启。 http://www.prolific.com.tw/admin/Technology/GetFile.ashx?fileID238 安装 minicom https://alioth.debian.org/projects/minicom/ 下载源码&…

macpro生成公钥并查看公钥

打开macpro的终端输入以下命令&#xff1a; $ cd ~/.ssh $ ls 此时发现没有那个id_rsa.pub文件&#xff0c;没有&#xff0c;就需要创建公钥 用ssh-keygen创建公钥 此时已经有了

java join 源码_join on 和where 一起使用的细节

left join :左连接&#xff0c;返回左表中所有的记录以及右表中连接字段相等的记录。right join :右连接&#xff0c;返回右表中所有的记录以及左表中连接字段相等的记录。inner join: 内连接&#xff0c;又叫等值连接&#xff0c;只返回两个表中连接字段相等的行。full join:外…

SSIS 学习之旅 FTP访问类

这章把脚本任务访问FTP的方法 全部给大家。 控件的使用大家如果有不懂得可以看下我之前的文章。第一章&#xff1a;SSIS 学习之旅 第一个SSIS 示例&#xff08;一&#xff09;&#xff08;上&#xff09; 第二章&#xff1a;SSIS 学习之旅 第一个SSIS 示例&#xff08;二&#…

Spring Cloud Feign 使用Apache的HTTP Client替换Feign原生httpclient

http 连接池能提升性能 http 的背景原理 a. 两台服务器建立 http 连接的过程是很复杂的一个过程&#xff0c;涉及到多个数据包的交换&#xff0c;并且也很耗时间。 b. Http 连接需要的 3 次握手 4 次分手开销很大&#xff0c;这一开销对于大量的比较小的 http 消息来说更大。…