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类型的将共享变量的操作加上同步一开始就将类设计成线程安全的, 比在后期重新修复它,更容易.编写多线程程序, 首先保证它 ...
随机推荐
- Linux-使用 screen 管理你的远程会话
转自:http://www.ibm.com/developerworks/cn/linux/l-cn-screen/ 你是不是经常需要 SSH 或者 telent 远程登录到 Linux 服务器?你是 ...
- Telnet使用
#使用telnet telnet #使用telnet,并连接到[ip] [port] telnet [ip] [port] baidu zone - telnet使用方法
- PHP 抽象类的使用
//抽象类就是一个模版 abstract class db{ /* 参数:sql语句 返回值:索引的数组 */ abstract public function test($str); //没有方法体 ...
- php学记笔记之函数用途
echo '<pre>';//格式化输出字符 isset();//判断变量是否存在 array_key_exists('key',$arr);//判断数组下标是否存在 in_array(' ...
- Windows下Python添加MySQLdb扩展模块
[更新 2012-09-16] 这里可以下载已经打包好的EXE文件,http://sourceforge.net/projects/mysql-python/(国内需穿越才可访问) DBank备份下载 ...
- Mysql各种类型字段长度
1.数值类型 列类型 需要的存储量 TINYINT 1 字节 SMALLINT 2 个字节 MEDIUMINT 3 个字节 INT 4 个字节 INTEGER 4 个字节 BIGINT 8 个字节 F ...
- cocos2dx 3.x simpleAudioEngine 长音效被众多短音效打断问题
假设先play长音效a,然后在a播放过程中反复执行:play短音效b,stop b,play b,... 则若a足够长,就会被b打断.而长音效被打断是最不可接受的. a之所以会被打断,推测原因是sim ...
- Atitit.判断元素是否显示隐藏在父元素 overflow
Atitit.判断元素是否显示隐藏在父元素 overflow 1.1. scrollTop 指的是元素的滚动条顶端距离原生基线的高度...1 1.2. 判断元素是否显示隐藏在父元素 $(next) ...
- 讲一下 Spring的事务传播特性
1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务.如果没有事务则开启 2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务.如果没有事 ...
- deepin linux下markdown实时预览
# deepin linux下markdown实时预览 ## 参考文章------------------------------ [vim安装markdown插件](http://www.jians ...