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系统中的load average
理解Linux系统中的load average(图文版) 博客分类: Linux linux load nagios 一.什么是load average? linux系统中的Load对当前CPU工作 ...
- SpringMVC 异常记录
在使用SpringMVC中开发过程中,遇到的一些坑,简单记录一下. 1.The request sent by the client was syntactically incorrect 从字面意思 ...
- 设置SSH编码为中文
http://www.qzz.in/?post=198下面是详细方法: 方法1: vi /etc/sysconfig/i18n 将内容改为 LANG="zh_CN.GB18030" ...
- CRC校验和网络通信中writen、readn函数
1.对网络传输的数据进行CRC32校验. #include <stdint.h> #include <stdio.h> #include <string.h> st ...
- ajax 上传图片
index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...
- Eclipse添加中文语言包与下载
从Eclipse官网下载最新版本的Eclipse都是英文版的,不自带语言包.现在Eclipse有一个语言包项目,叫Eclipse Babel Project.如果需要语言包,可以联机从这儿下载. Ba ...
- linux命令小技巧
一:命令行里怎么往上翻页 Shift+PageUP|PageDown 二:分页显示文件内容则可以用less工具过滤,然后用方向键或PageUp/PageDown上下翻 less /etc/passwd ...
- 【Android界面实现】View Animation 使用介绍
转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 我们能够使用view animation 动画系统来给View控件加入tween动画(下称& ...
- Unity中差乘判断目标是否在左边或右边
使用差乘判断左右一般是比较差乘的y,小于0是左,大于0是右.特殊情况可以用其他分量来比较 默认情况: var cross = Vector3.Cross(lhsObject.transform.pos ...
- SQL server账号无法登陆