将AtomicInteger对象作为方法的局部变量, 传递给其他线程, 读写操作是否是线程安全的?
将AtomicInteger对象作为方法的局部变量, 传递给其他线程, 读写操作是否是线程安全的?
场景
在main线程中, 有一个方法名为triggerSomeThreadWithMethodLocalVariable, 该方法会启动一些线程并且带着该方法里的一个类型为AtomicInteger的局部变量(一般写代码是把线程共享的变量作为类的成员变量),每个线程对该变量的局部变量atomicInteger进行写操作, atomicInteger变量是否在线程间持续可见并且线程安全?
代码
/**
* @author rhyme
*/
@Slf4j
public class MethodLocalVariableMain {
public static void main(String[] args) {
final MethodLocalVariableMain methodLocalVariableMain = new MethodLocalVariableMain();
final AtomicInteger atomicInteger = new AtomicInteger(10);
methodLocalVariableMain.triggerSomeThreadWithMethodLocalVariable(atomicInteger);
}
public void triggerSomeThreadWithMethodLocalVariable(AtomicInteger atomicInteger) {
final int threadCount = 10;
CompletableFuture[] completableFutures = new CompletableFuture[threadCount];
for (int i = 0; i < threadCount; i++) {
completableFutures[i] =
CompletableFuture.runAsync(
() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
log.error("InterruptedException happen when TimeUnit.SECONDS.sleep(3);", e);
Thread.currentThread().interrupt();
}
log.info(
"ThreadName: {}, atomicInteger.decrementAndGet(): {}.",
Thread.currentThread().getName(),
atomicInteger.decrementAndGet());
});
}
// 等待所有CompletableFuture线程执行完毕
CompletableFuture.allOf(completableFutures).join();
log.info(
"In main thread, after all completableFuture is finished, threadName: {}, atomicInteger.get(): {}.",
Thread.currentThread().getName(),
atomicInteger.get());
}
}
上述代码流程见上面的"场景"描述.
运行结果
在4核8逻辑处理测试结果如下:
ThreadName: ForkJoinPool.commonPool-worker-1, atomicInteger.decrementAndGet(): 3.
ThreadName: ForkJoinPool.commonPool-worker-7, atomicInteger.decrementAndGet(): 5.
ThreadName: ForkJoinPool.commonPool-worker-3, atomicInteger.decrementAndGet(): 6.
ThreadName: ForkJoinPool.commonPool-worker-6, atomicInteger.decrementAndGet(): 4.
ThreadName: ForkJoinPool.commonPool-worker-2, atomicInteger.decrementAndGet(): 9.
ThreadName: ForkJoinPool.commonPool-worker-5, atomicInteger.decrementAndGet(): 7.
ThreadName: ForkJoinPool.commonPool-worker-4, atomicInteger.decrementAndGet(): 8.
ThreadName: ForkJoinPool.commonPool-worker-3, atomicInteger.decrementAndGet(): 0.
ThreadName: ForkJoinPool.commonPool-worker-7, atomicInteger.decrementAndGet(): 2.
ThreadName: ForkJoinPool.commonPool-worker-1, atomicInteger.decrementAndGet(): 1.
In main thread, after all completableFuture is finished, threadName: main, atomicInteger.get(): 0.
总结
根据结果来看, 被main线程方法传递的atomicInteger变量, 它的value属性在新启动的各个线程是线程安全, 并且value持续可见;
原理是, 传递的是atomicInteger变量的引用, 即多个线程持有的是同一份atomicInteger变量的引用, 并且利用了AtomicInteger的特性(CAS修改被volatile修饰的变量value, 对value操作的原子性以及变量value在多线程间的可见性);
虽然结果是正确的, 但是还是不建议这样使用方法的局部变量, 这样可能会发生线程逃逸等问题;
线程之间的共享变量, 还是应该作为对象的成员变量更好, 这才是常见的规范写法.
将AtomicInteger对象作为方法的局部变量, 传递给其他线程, 读写操作是否是线程安全的?的更多相关文章
- Activity传递对象的方法
//Serializeable传递对象的方法 public void SerializeMethod(){ Person mPerson = new Person(); mPerson.setName ...
- java类(Class)的概念;对象的概念,声明类的属性 和方法,局部变量和成员变量,面向对象编程思维,抽象的概念
类(Class)的概念 类是对一组具有相同特征和行为的对象的抽象描述. 理解: [1] 类包含了两个要素:特性和行为 => 同一类事物具有相同的特征和行为. [2] 类是一个群体性概念.例如:网 ...
- request对象的方法及其参数的传递
先设计一个简单的登录界面index.htm: <html><head><title>request的使用</title></head>< ...
- 【java】值传递和引用传递---对象作为方法的参数传入属于哪种传递
首先 这篇作为一个永久性的问题,欢迎大家讨论 其次,个人结论如下几条: ①Java有且只有一种传递,即 值传递 ②作为方法的参数传入,都是对原本的实参进行了copy ③只不过[实参]若是[基本数据类型 ...
- 《Java从入门到失业》第四章:类和对象(4.4):方法参数及传递
4.4方法参数及传递 关于这个知识点,我想了很久该不该在这里阐述.因为这个知识点稍微有点晦涩,并且就算不了解也不影响用Java编写代码.不过笔者刚开始工作的时候,就是因为这块内容没有过多的关注,以至于 ...
- 面向对象、类与对象、成员与局部变量、封装、private、构造函数、this、static、extends、super、final、abstract、interface、多态、内部类、异常【5】
若有不正之处,请多多谅解并欢迎批评指正,不甚感激. 请尊重作者劳动成果: 本文原创作者:pipi-changing本文原创出处:http://www.cnblogs.com/pipi-changing ...
- 1、探究java方法参数传递——引用传递?值传递!
原创博文,转载请注明出处.谢谢~~ java程序运行时,其对象是怎么进行放置和安排的呢?内存是怎么分配的呢?理解好这个很有好处!java有5个地方可以存储数据: 1.寄存器.这是最快的存储区,位于处理 ...
- JS中的对象和方法简单剖析
众所周知,在js中对象就是精髓,不理解对象就是不理解js. 那么什么事js中的对象呢? 在js中,几乎一切皆对象: Boolean ,String,Number可以是对象(或者说原生数据被认作对象): ...
- Java中类,对象,方法的内存分配
Java中类,对象,方法的内存分配 以下针对引用数据类型: 在内存中,类是静态的概念,它存在于内存中的CodeSegment中. 当我们使用new关键字生成对象时,JVM根据类的代码,去堆内存中开辟一 ...
- Objective-C之成魔之路【7-类、对象和方法】
郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠.支持郝萌主,捐赠数额任意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 Objec ...
随机推荐
- DeepSeek 多模态模型 Janus-Pro 本地部署
一.概述 Janus-Pro是DeepSeek最新开源的多模态模型,是一种新颖的自回归框架,统一了多模态理解和生成.通过将视觉编码解耦为独立的路径,同时仍然使用单一的.统一的变压器架构进行处理,该框架 ...
- 【.NET必读】RabbitMQ 4.0+重大变更!C#开发者必须掌握的6大升级要点
RabbitMQ 作为一款广受欢迎的消息队列中间件,近年来从 3.x 版本升级到 4.0+,带来了显著的功能增强和架构调整.与此同时,其官方 C# 客户端也从 6.x 版本跃升至 7.0,引入了全新的 ...
- css——慕课
- .NET 的全新低延时高吞吐自适应 GC - Satori GC
GC 的 STW 问题 GC,垃圾回收器,本质上是一种能够自动管理自己分配的内存的生命周期的内存分配器.这种方法被大多数流行编程语言采用,然而当你使用垃圾回收器时,你会失去对应用程序如何管理内存的控制 ...
- Spring Boot微服务设置logback日志打印级别并关闭kafka debug日志
摘要:以关闭Spring Boot微服务kafka日志为例,介绍logback日志框架中logger标签的属性. 问题描述 在Spring Boot整合kafka的时候,日志配置使用 logbac ...
- 转|java反射方法和使用
概述 java中不通过new关键字获取对象并且使用类对象中的成员变量和方法,第一时间我们会想到可以使用反射去实现这些功能.反射很强大,而且是Spring的常用轮子,故我们学会了它就可以搭配很多东西 ...
- Spring注解之@Autowired:Setter 方法上使用@Autowired注解
可以在 JavaBean中的 setter 方法中使用 @Autowired 注解.当 Spring遇到一个在 setter 方法中使用的 @Autowired 注解时,它会在方法中按照类型自动装配参 ...
- java实现一个接口多个实现类,并且依次调用指定方法
接口 package cn.daenx.yhchatsdk.mytest; public interface MyInterface { /** * 返回-1,后面的实现类将不再执行 * 返回0,后面 ...
- kubernetes集群GPU支持方案
一.kubernetes对GPU的支持版本 kubernetes提供对分布式节点上的AMD GPU和NVIDIA GPU管理的实验性的支持.在V1.6中已经添加了对NVIDIA GPU的支持,并且经历 ...
- Python全栈应用开发利器Dash 3.x新版本介绍(4)
更多Dash应用开发干货知识.案例,欢迎关注"玩转Dash"微信公众号 大家好我是费老师,在前几期文章中,我们针对Python生态中强大且灵活的全栈应用开发框架Dash,介绍了其3 ...