java 线程安全原子性_Java 线程安全之原子性
Java 线程安全之原子性
Java 线程安全之原子性
原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可被打乱,也不可以被切割而执行其中的一部分(不可中断)。将整个操作视为一个整体是原子性的核心特征。
首先看下面这样一段代码,两个线程都对count变量进行自加操作10000次
public class ThreadSecurityDemo {
private long count = 0;
public void test() throws InterruptedException {
for (int i = 2; i > 0; i--) {
new Thread(()->{
for (int j = 0; j < 10000; j++) {
count++;
}
}).start();
}
Thread.sleep(1000);
System.out.println(count);
}
public static void main(String[] args) throws InterruptedException {
ThreadSecurityDemo demo = new ThreadSecurityDemo();
demo.test();
}
}
运行结果如下:
按理来说count的值应该是20000,但实际上却不是,这就出现了线程安全问题,为了解决这个问题,我们可以使用同步代码块。
test方法修改如下:
public void test() throws InterruptedException {
for (int i = 2; i > 0; i--) {
new Thread(()->{
for (int j = 0; j < 10000; j++) {
synchronized (this)
{
count++;
}
}
}).start();
}
Thread.sleep(1000);
System.out.println(count);
}
实际上,java的J.U.C包内为我们提供了原子操作的封装类:
AtomicBoolean: 原子更新布尔类型
AtomicInteger:原子更新整型
AtomicLong:原子更新长整型
等等…
使用很简单,我们使用AtomicLong来解决上面的问题
import java.util.concurrent.atomic.AtomicLong;
public class ThreadSecurityDemo {
private AtomicLong atoacount= new AtomicLong(0L);
public void test() throws InterruptedException {
for (int i = 2; i > 0; i--) {
new Thread(()->{
for (int j = 0; j < 10000; j++) {//自增
atoacount.incrementAndGet();
}
}).start();
}
Thread.sleep(1000);
System.out.println(atoacount);
}
public static void main(String[] args) throws InterruptedException {
ThreadSecurityDemo demo = new ThreadSecurityDemo();
demo.test();
}
}
虽然效果一样,但是这种方法的执行效率比同步代码块高。
jdk1.8后加入了LongAdder,DoubleAdder的计数器,在高并发情况下性能更好,同样能够解决这个问题。
LongAdder会将一个数据分成多个操作单元,不同的线程更新不同的单元,只要需要汇总的时候才计算所有单元的操作。
import java.util.concurrent.atomic.LongAdder;
public class ThreadSecurityDemo {
private LongAdder lacount = new LongAdder();
public void test() throws InterruptedException {
for (int i = 2; i > 0; i--) {
new Thread(()->{
for (int j = 0; j < 10000; j++) {
lacount.increment();
}
}).start();
}
Thread.sleep(1000);
System.out.println(lacount.sum());
}
public static void main(String[] args) throws InterruptedException {
ThreadSecurityDemo demo = new ThreadSecurityDemo();
demo.test();
}
}
下面我们通过三者在两秒钟内执行的次数来比较执行效率
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
public class ThreadSecurityDemo {
private int count=0;
// 同步代码块的方式
public void testSync() throws InterruptedException {
for (int i = 0; i < 3; i++) {
new Thread(() -> {
long starttime = System.currentTimeMillis();
while (System.currentTimeMillis() - starttime < 2000) { // 运行两秒
synchronized (this) {
++count;
}
}
long endtime = System.currentTimeMillis();
System.out.println("同步代码块执行时间:" + (endtime - starttime) + "毫秒," + "执行自加次数:" + count);
}).start();
}
}
// Atomic方式
private AtomicLong acount = new AtomicLong(0L);
public void testAtomic() throws InterruptedException {
for (int i = 0; i < 3; i++) {
new Thread(() -> {
long starttime = System.currentTimeMillis();
while (System.currentTimeMillis() - starttime < 2000) {
acount.incrementAndGet();
}
long endtime = System.currentTimeMillis();
System.out.println("Atomic方式执行时间:" + (endtime - starttime) + "毫秒," + "执行自加次数:" + acount.incrementAndGet());
}).start();
}
}
// LongAdder 方式
private LongAdder lacount = new LongAdder();
public void testLongAdder() throws InterruptedException {
for (int i = 0; i < 3; i++) {
new Thread(() -> {
long starttime = System.currentTimeMillis();
while (System.currentTimeMillis() - starttime < 2000) {
lacount.increment();
}
long endtime = System.currentTimeMillis();
System.out.println("LongAdder方式执行时间:" + (endtime - starttime) + "毫秒," + "执行自加次数:" + lacount.sum());
}).start();
}
}
public static void main(String[] args) throws InterruptedException {
ThreadSecurityDemo demo = new ThreadSecurityDemo();
demo.testSync();
demo.testAtomic();
demo.testLongAdder();
}
}
通过执行次数我们可以直观比较执行效率:
LongAdder方式 > AtomicLong方式 > 同步代码块方式
Java 线程安全之原子性相关教程
java基础知识点笔记
java基础知识点笔记 基础知识点 abstract表明类或者成员方法具有抽象属性assert断言,用来进行程序调试boolean基本数据类型之一,声明布尔类型的关键字break提前跳出一个块byte基本数据类型之一,字节类型case用在switch语句之中,表示其中的一个分支catch用
蓝桥杯第六届牌型种数(Java)
蓝桥杯第六届牌型种数(Java) 暴力: public class Main { public static void main(String[] args) { int[] a = new int[13]; int count = 0; for (a[0] = 0; a[0] = 4; a[0]++) for (a[1] = 0; a[1] = 4; a[1]++) for (a[2] = 0; a[2] = 4; a[2]++) for (a
第76课 多线程间的互斥(下)
第76课 多线程间的互斥(下) 一、多线程间的互斥 问题:程序有多少临界资源?需要多少线程锁? 一般性原则:每一个临界资源都需要一个线程锁进行保护 死锁发生: main.cpp #include QCoreApplication#include QThread#include QDebug#include QMutexQMutex g
java学习笔记day2【基础语法】
java学习笔记day2【基础语法】 二、语法 ps:基本常识 熟悉psvm和sout 可以执行 改注释颜色的时候遇到些问题,可能是因为免费版改不了,画圈的都点不了 //单行注释/*多行注释多行注释多行注释*/ 注意事项: 所有的标识符都应该以字母、$、或者_开头。 首字母
Java NIO学习,一次读懂Java NIO
Java NIO学习,一次读懂Java NIO Java NIO 和 IO 的区别 缓冲区存取数据的两个核心方法 put:存入数据到缓冲区 get:获取缓冲区中的数据 缓冲区的四个核心属性 capacity:容量,表示缓冲区中最大存储数据的容量,一旦声明不能改变 position:位置,表示缓冲区
Java运行时数据区(Run-time data areas)
Java运行时数据区(Run-time data areas) Run-time data areas PC (program counter):存放指令位置 虚拟机的运行类似如下循环 while(not end) {取PC中的位置,找到对应位置的指令;执行该指令;PC++;} JVM stacks :每个java线程独有一个栈,里面装的是栈帧,
Getting started with Java EE 8 MVC(1)
Getting started with Java EE 8 MVC(1) 为什么80%的码农都做不了架构师? Getting started with Java EE 8 MVC MVC is a new specification introduced in the upcoming Java EE 8. It is based on the existing JAXRS. At the moment I wrote down these po
LintCode 213. 字符串压缩 JavaScript算法
LintCode 213. 字符串压缩 JavaScript算法 描述 设计一种方法,通过给重复字符计数来进行基本的字符串压缩。 例如,字符串 aabcccccaaa 可压缩为 a2b1c5a3 。而如果压缩后的字符数不小于原始的字符数,则返回原始的字符串。 可以假设字符串仅包括 a-z 的字母
java 线程安全原子性_Java 线程安全之原子性相关推荐
- java 同步转并行_Java线程与并行编程(二)
你好,我是goldsunC 让我们一起进步吧! 线程的控制与同步 线程的状态与生命周期 '每个Java程序都有一个默认的主线程,想要实现多线程,必须在主线程中创建新的线程对象.新建的线程在它的一个完整 ...
- java方法生命周期_Java线程的第二种实现方式以及生命周期
上篇中我们了解了Java线程的第一种实现方式,主要分两步,第一步是继承java.lang.Thread; 第二步是重写run()方法.接下来我们来看Java线程的第二种实现方式,也是分为两步,第一步, ...
- java 线程 状态 图_Java线程中的生命周期和状态控制图文详解
这篇文章主要介绍了Java线程的生命周期和状态控制,需要的朋友可以参考下 一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于 ...
- java 线程栈空间_java线程的内存不包含在JVM堆与栈中
Java代码 publicclassMaxThreadsTest { publicstaticvoidmain(String[] args) { while(true) { newThread(n ...
- java io密集型任务_Java线程池讲解——针对IO密集型任务
sap java开发技术详解&mdash基础 94.01元 (需用券) 去购买 > 针对 IO 密集型的任务,我们可以针对原本的线程池做一些改造,从而可以提高任务的处理效率. 基本 在阿 ...
- java线程不执行_java线程池,阿里为什么不允许使用Executors?
带着问题 阿里Java代码规范为什么不允许使用Executors快速创建线程池? 下面的代码输出是什么? ThreadPoolExecutor executor = new ThreadPoolExe ...
- java 线程组作用_Java线程组(ThreadGroup)使用
JDK 对线程组类注释: A thread group represents a set of threads. In addition, a thread group can also includ ...
- java中一个线程最小优先数_Java线程的优先级
Java线程可以有优先级的设定,高优先级的线程比低优先级的线程有更高的几率得到执行(不完全正确,请参考下面的"线程优先级的问题"). 记住当线程的优先级没有指定时,所有线程都携带普 ...
- java线程池执行器_Java线程池ThreadPoolExecutor的使用
Java线程池ThreadPoolExecutor的使用 ThreadPoolExecutor就是我们用来实现线程的一个执行器,它实现了Excutor和ExecutorService接口.Excuto ...
- java线程详解_Java线程详解
程序.进程.线程的概念程序(program):是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码,静态对象. 进程(process):是程序的一次执行过程,或是正在运行的一个程序.动 ...
最新文章
- MavenAnt使用
- 大数据容器化-基于Kubernetes(k8s)构建spark运行环境
- 在VS2010里可以给JS函数添加代码提示\注释
- ACDream - Dynamic Inversions II
- 刘奕佳: 我的职校新生活 | 班级日常分享
- Java加密与解密的艺术~数字签名~DSA实现
- OpenCart多图片拖放式上传管理器
- LabVIEW程序快速开发流程
- .NetCore对接各大财务软件凭证API——金蝶系列(2)
- mobilenet cpu 加速_UP手游加速器苹果版下载安装-UP手游加速器iOS苹果版下载
- 网页错误代码汇总(整理不易,用心记住)
- linux fstab错误无法启动,Linux 系统 fstab错误导致系统无法启动的修复
- 华硕重装后进入bios_重装系统以后,开机自动进bios,进不了系统怎么办
- 计算机 90学时培训总结,90学时的培训心得体会
- matlab中多元线性回归regress函数精确剖析(附实例代码)
- 计算机为啥启用不了网络发现,win7系统“网络发现”功能启用不了的解决方法...
- 如何在iPhone手机上安装ipa(应用安装包)
- 计算机的内存条比硬盘,电脑硬盘比内存条还小,全是这个协议的功劳!
- 函数有参无参真有很大区别吗?
- 为什么rand()每次产生的随机数都一样
热门文章
- tsm2812通用定时器中断_通用定时器中断(TIM2)
- 如何用python打印田字格_如何用EXCEL做一套田字格模板?在家给小孩练习写字
- C语言 用传统流程图表示分段函数,C语言程序设计习题答案
- textfield获取其中内容_冲压工艺流程,常见冲压缺陷及消除方法,46页内容全面介绍冲压...
- 自建服务器打印机,关于Windows 2016 Server创建打印机服务器后对打印机设置权限的问题...
- kallsyms 压缩_initrd.img、System.map学习札记
- graphpad prism显著性差异分析_【市场表现】2020年第三季度企业债利差分析
- java .equal_Java 中的equals()方法
- mysql utf8转gbk cmd_utf8转成gbk
- 基金指数温度怎么算_结构粘钢胶流淌很严重怎么办?