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 线程安全之原子性相关推荐

  1. java 同步转并行_Java线程与并行编程(二)

    你好,我是goldsunC 让我们一起进步吧! 线程的控制与同步 线程的状态与生命周期 '每个Java程序都有一个默认的主线程,想要实现多线程,必须在主线程中创建新的线程对象.新建的线程在它的一个完整 ...

  2. java方法生命周期_Java线程的第二种实现方式以及生命周期

    上篇中我们了解了Java线程的第一种实现方式,主要分两步,第一步是继承java.lang.Thread; 第二步是重写run()方法.接下来我们来看Java线程的第二种实现方式,也是分为两步,第一步, ...

  3. java 线程 状态 图_Java线程中的生命周期和状态控制图文详解

    这篇文章主要介绍了Java线程的生命周期和状态控制,需要的朋友可以参考下 一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于 ...

  4. java 线程栈空间_java线程的内存不包含在JVM堆与栈中

    Java代码   publicclassMaxThreadsTest { publicstaticvoidmain(String[] args) { while(true) { newThread(n ...

  5. java io密集型任务_Java线程池讲解——针对IO密集型任务

    sap java开发技术详解&mdash基础 94.01元 (需用券) 去购买 > 针对 IO 密集型的任务,我们可以针对原本的线程池做一些改造,从而可以提高任务的处理效率. 基本 在阿 ...

  6. java线程不执行_java线程池,阿里为什么不允许使用Executors?

    带着问题 阿里Java代码规范为什么不允许使用Executors快速创建线程池? 下面的代码输出是什么? ThreadPoolExecutor executor = new ThreadPoolExe ...

  7. java 线程组作用_Java线程组(ThreadGroup)使用

    JDK 对线程组类注释: A thread group represents a set of threads. In addition, a thread group can also includ ...

  8. java中一个线程最小优先数_Java线程的优先级

    Java线程可以有优先级的设定,高优先级的线程比低优先级的线程有更高的几率得到执行(不完全正确,请参考下面的"线程优先级的问题"). 记住当线程的优先级没有指定时,所有线程都携带普 ...

  9. java线程池执行器_Java线程池ThreadPoolExecutor的使用

    Java线程池ThreadPoolExecutor的使用 ThreadPoolExecutor就是我们用来实现线程的一个执行器,它实现了Excutor和ExecutorService接口.Excuto ...

  10. java线程详解_Java线程详解

    程序.进程.线程的概念程序(program):是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码,静态对象. 进程(process):是程序的一次执行过程,或是正在运行的一个程序.动 ...

最新文章

  1. MavenAnt使用
  2. 大数据容器化-基于Kubernetes(k8s)构建spark运行环境
  3. 在VS2010里可以给JS函数添加代码提示\注释
  4. ACDream - Dynamic Inversions II
  5. 刘奕佳: 我的职校新生活 | 班级日常分享
  6. Java加密与解密的艺术~数字签名~DSA实现
  7. OpenCart多图片拖放式上传管理器
  8. LabVIEW程序快速开发流程
  9. .NetCore对接各大财务软件凭证API——金蝶系列(2)
  10. mobilenet cpu 加速_UP手游加速器苹果版下载安装-UP手游加速器iOS苹果版下载
  11. 网页错误代码汇总(整理不易,用心记住)
  12. linux fstab错误无法启动,Linux 系统 fstab错误导致系统无法启动的修复
  13. 华硕重装后进入bios_重装系统以后,开机自动进bios,进不了系统怎么办
  14. 计算机 90学时培训总结,90学时的培训心得体会
  15. matlab中多元线性回归regress函数精确剖析(附实例代码)
  16. 计算机为啥启用不了网络发现,win7系统“网络发现”功能启用不了的解决方法...
  17. 如何在iPhone手机上安装ipa(应用安装包)
  18. 计算机的内存条比硬盘,电脑硬盘比内存条还小,全是这个协议的功劳!
  19. 函数有参无参真有很大区别吗?
  20. 为什么rand()每次产生的随机数都一样

热门文章

  1. tsm2812通用定时器中断_通用定时器中断(TIM2)
  2. 如何用python打印田字格_如何用EXCEL做一套田字格模板?在家给小孩练习写字
  3. C语言 用传统流程图表示分段函数,C语言程序设计习题答案
  4. textfield获取其中内容_冲压工艺流程,常见冲压缺陷及消除方法,46页内容全面介绍冲压...
  5. 自建服务器打印机,关于Windows 2016 Server创建打印机服务器后对打印机设置权限的问题...
  6. kallsyms 压缩_initrd.img、System.map学习札记
  7. graphpad prism显著性差异分析_【市场表现】2020年第三季度企业债利差分析
  8. java .equal_Java 中的equals()方法
  9. mysql utf8转gbk cmd_utf8转成gbk
  10. 基金指数温度怎么算_结构粘钢胶流淌很严重怎么办?