AtomicInteger保证线程安全的全局变量
现有业务场景需要做一个线程间的全局变量,并且实现自增效果。
初始使用了volatile 来保证count的安全性,如下:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; public class TestThredd { private volatile int count = 0; public void increment() {
count++;
} private int getCount() {
return count;
} /**
* 这里模拟一个递增的任务,递增目标为50000
*/
public static void main(String[] args) throws InterruptedException {
final TestThredd counter = new TestThredd();
int workCount = 50000;
ExecutorService executor = Executors.newFixedThreadPool(10);
long start = System.currentTimeMillis();
for (int i = 0; i < workCount; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
counter.increment();
}
};
executor.execute(runnable);
}
// 关闭启动线程,执行未完成的任务
executor.shutdown();
// 等待所有线程完成任务,完成后才继续执行下一步
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms");
System.out.println("执行结果:count=" + counter.getCount());
}
}
执行结果

它的结果不是我们预料的50000 .通常我们需要加上在count++时 加上synchronized关键字,保证他的正确性。
如下:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; public class TestThredd { private volatile int count = 0; /**
* 为了保证数据的准确性,多线程的情况下需要加上synchronized关键字
* 否则会出现出乎预料的结果 这也是线程安全的重要体现
*/
public synchronized void increment() {
count++;
} private int getCount() {
return count;
} /**
* 这里模拟一个递增的任务,递增目标为50000
*/
public static void main(String[] args) throws InterruptedException {
final TestThredd counter = new TestThredd();
int workCount = 50000;
ExecutorService executor = Executors.newFixedThreadPool(10);
long start = System.currentTimeMillis();
for (int i = 0; i < workCount; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
counter.increment();
}
};
executor.execute(runnable);
}
// 关闭启动线程,执行未完成的任务
executor.shutdown();
// 等待所有线程完成任务,完成后才继续执行下一步
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms");
System.out.println("执行结果:count=" + counter.getCount());
}
}

为了保证数据的准确性,多线程的情况下需要加上synchronized关键字,否则会出现不安全的操作
如果我们换个方式,用AtomicInteger来替换count++,怎么做呢?
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { private AtomicInteger count = new AtomicInteger(0); // 使用AtomicInteger之后,不需要加锁,也可以实现线程安全。
public void increment() {
//获取当前的值并自增
count.incrementAndGet();
}
/**
* 获取当前的值
* @return
*/
public int getCount() {
return count.get();
}
//递减
public void deIncrement(){
count.decrementAndGet();
} /**
* 这里模拟一个递增的任务,递增目标为50000
*/
public static void main(String[] args) throws InterruptedException {
final AtomicCounter counter = new AtomicCounter();
int workCount = 50000;
ExecutorService executor = Executors.newFixedThreadPool(10);
long start = System.currentTimeMillis();
for (int i = 0; i < workCount; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
counter.increment();
}
};
executor.execute(runnable);
}
// 关闭启动线程,执行未完成的任务
executor.shutdown();
// 等待所有线程完成任务,完成后才继续执行下一步
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms");
System.out.println("执行结果:count=" + counter.getCount());
}
}

AtomicInteger很轻松的实现了线程安全的变量操作
Java从JDK 1.5开始提供了java.util.concurrent.atomic包(以下简称Atomic包),这个包中的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式。因为变量的类型有很多种,所以在Atomic包里一共提供了13个类,属于4种类型的原子更新方式,分别是原子更新基本类型、原子更新数组、原子更新引用和原子更新属性(字段)。Atomic包里的类基本都是使用Unsafe实现的包装类。
使用原子的方式更新基本类型,Atomic包提供了以下3个类。
AtomicBoolean:原子更新布尔类型。
AtomicInteger:原子更新整型。
AtomicLong:原子更新长整型。
通过原子的方式更新数组里的某个元素,Atomic包提供了以3类
AtomicIntegerArray:原子更新整型数组里的元素。
AtomicLongArray:原子更新长整型数组里的元素。
AtomicReferenceArray:原子更新引用类型数组里的元素。
AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减。
AtomicInteger是在使用非阻塞算法实现并发控制,在一些高并发程序中非常适合,但并不能每一种场景都适合,不同场景要使用使用不同的数值类。
这是由硬件提供原子操作指令实现的,这里面用到了一种并发技术:CAS。在非激烈竞争的情况下,开销更小,速度更快。
参考:
http://blog.csdn.net/sunxianghuang/article/details/52277370
http://blog.csdn.net/u012734441/article/details/51619751
http://blog.csdn.net/jan_s/article/details/47025095
AtomicInteger保证线程安全的全局变量的更多相关文章
- 最近面试被问到一个问题,AtomicInteger如何保证线程安全?
最近面试被问到一个问题,AtomicInteger如何保证线程安全?我查阅了资料 发现还可以引申到 乐观锁/悲观锁的概念,觉得值得一记. 众所周知,JDK提供了AtomicInteger保证对数字的操 ...
- AtomicInteger如何保证线程安全以及乐观锁/悲观锁的概念
众所周知,JDK提供了AtomicInteger保证对数字的操作是线程安全的,线程安全我首先想到了synchronized和Lock,但是这种方式又有一个名字,叫做互斥锁,一次只能有一个持有锁的线程进 ...
- 多线程下C#如何保证线程安全?
多线程编程相对于单线程会出现一个特有的问题,就是线程安全的问题.所谓的线程安全,就是如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是 ...
- ASP.NET MVC Filters 4种默认过滤器的使用【附示例】 数据库常见死锁原因及处理 .NET源码中的链表 多线程下C#如何保证线程安全? .net实现支付宝在线支付 彻头彻尾理解单例模式与多线程 App.Config详解及读写操作 判断客户端是iOS还是Android,判断是不是在微信浏览器打开
ASP.NET MVC Filters 4种默认过滤器的使用[附示例] 过滤器(Filters)的出现使得我们可以在ASP.NET MVC程序里更好的控制浏览器请求过来的URL,不是每个请求都会响 ...
- C#多线程下如何保证线程安全?
多线程编程相对于单线程会出现一个特有的问题,就是线程安全的问题.所谓的线程安全,就是如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是 ...
- Java中如何保证线程顺序执行
只要了解过多线程,我们就知道线程开始的顺序跟执行的顺序是不一样的.如果只是创建三个线程然后执行,最后的执行顺序是不可预期的.这是因为在创建完线程之后,线程执行的开始时间取决于CPU何时分配时间片,线程 ...
- 解析ThreadPoolExecutor类是如何保证线程池正确运行的
摘要:对于线程池的核心类ThreadPoolExecutor来说,有哪些重要的属性和内部类为线程池的正确运行提供重要的保障呢? 本文分享自华为云社区<[高并发]通过源码深度解析ThreadPoo ...
- EF 保证线程内唯一 上下文的创建
1.ef添加完这个对象,就会自动返回这个对象数据库的内容,比如下面这个表是自增ID 最后打印出来的ID 就是自增的结果 2.lambda 中怎么select * var userInfoList = ...
- 在JAVA中ArrayList如何保证线程安全
[b]保证线程安全的三种方法:[/b]不要跨线程访问共享变量使共享变量是final类型的将共享变量的操作加上同步一开始就将类设计成线程安全的, 比在后期重新修复它,更容易.编写多线程程序, 首先保证它 ...
随机推荐
- MySQL外键的设置及作用
原文地址:http://www.php100.com/html/webkaifa/database/Mysql/2010/0830/5342.html 外键的作用: 保持数据一致性,完整性,主要目的是 ...
- Cacti监控MySQL实现过程中碰到的问题解汇总
前言:cacti监控mysql服务器的大概50张graphs都弄出来了,也出图了,当中遇到一些问题,印象比較深刻的记录例如以下: (一):加入io监控 点击Create Graphs for this ...
- SSH面试题目
一简答 spring工作原理 为什么要用spring 3.请你谈谈SSH整合 4.介绍一下Spring的事务管理 5.Struct2基本流程 6.在Hibernate应用中Java对象的状态有哪些? ...
- 批量删除git分支
本篇文章由:http://xinpure.com/bulk-delete-git-branching/ 批量删除git分支 使用 git 时候,经常会发现,不知不觉就创建了大量的分支.那么,麻烦事就来 ...
- oracle 使用REGEXP_SUBSTR正则表达式拆分字符串
SELECT REGEXP_SUBSTR ('first field, second field , third field', '[^,]+', 1,rownum) FROM DUAL CONNEC ...
- JavaScript中逻辑运算符
一.JavaScript“逻辑”运算符 很多学习 JavaScript的人,容易被 JavaScript 的逻辑运算符的运算规则搞晕.为什么呢?因为JavaScript的逻辑运算符和其他语言(比如:j ...
- discuz开发笔记
http://blog.csdn.net/tiangsu_php/article/details/7665125 http://www.discuz.net/thread-3225192-1-1.ht ...
- sublime for mac 注册码
https://www.jianshu.com/p/04e1b65dd2c0https://fatesinger.com/100121
- git 清除历史
http://stackoverflow.com/questions/9683279/make-the-current-commit-the-only-initial-commit-in-a-git- ...
- python list.remove(),del()和filter & lambda
面试题之中的一个. 下面代码能执行吗? l = [1,2,3,4,5] for i in range(0,len(l)): print i if l[i] % 2 == 0: del l[i] pri ...