Java 我们能在方法中使用AtomicInteger作为局部变量并实现线程安全吗? public void tSafe(列表、属性状态){ if(list==null)返回; String key=“COUNT”; AtomicInteger a=新的AtomicInteger(Integer.valueOf(status.getProperty(key,“0”)); list.parallelStream().filter(Foo::check)。 forEach(foo->{status.setProperty(key,String.valueOf(a.incrementAndGet());} ); } 专用接口Foo{ 公共布尔检查(); }
说明:Java 我们能在方法中使用AtomicInteger作为局部变量并实现线程安全吗? public void tSafe(列表、属性状态){ if(list==null)返回; String key=“COUNT”; AtomicInteger a=新的AtomicInteger(Integer.valueOf(status.getProperty(key,“0”)); list.parallelStream().filter(Foo::check)。 forEach(foo->{status.setProperty(key,String.valueOf(a.incrementAndGet());} ); } 专用接口Foo{ 公共布尔检查(); },java,multithreading,Java,Multithreading,说明: 在上面的示例中,status是一个共享属性,它包含一个名为COUNT的键。我的目标是增加计数并将其放回属性中,以计算执行的检查数。考虑TFAID方法是由多个线程调用的,在结尾处我得到正确的计数吗?请注意,我使用了AtomicInteger a作为局部变量。如果只有一个线程,这将起作用,但是如果有多个线程调用它,则会有一些线程安全的操作。如果每个线程在不同的列表和状态对象上运行,这将是很好的 由于status是线程安全的集合,您可以锁定它,如果列表在另一个线程中没有更改,则这将是安全的 一
在上面的示例中,status是一个共享属性,它包含一个名为COUNT的键。我的目标是增加计数并将其放回属性中,以计算执行的检查数。考虑TFAID方法是由多个线程调用的,在结尾处我得到正确的计数吗?请注意,我使用了AtomicInteger a作为局部变量。如果只有一个线程,这将起作用,但是如果有多个线程调用它,则会有一些线程安全的操作。如果每个线程在不同的
列表
和状态
对象上运行,这将是很好的
由于status
是线程安全的集合,您可以锁定它,如果列表
在另一个线程中没有更改,则这将是安全的
一般来说,以线程安全的方式使用字符串作为数字是非常棘手的。你最好让你的值线程,即原子整数,而不是其他任何东西。不,这不能保证线程安全。尽管
incrementAndGet()
本身是原子的,但从属性
对象获取值并将其设置回原来的值并不是原子的
考虑以下场景:
属性
对象获取一个值。为了辩论起见,我们假设它是“100”属性
对象获取一个值。由于没有发生任何情况,该值仍然为“100”原子整数
,将其递增,并在属性
对象中放置“101”Properties
对象中,而不是预期的102更有效的方法是,将
原子整数存储在状态图上,并在原地递增。这样,您就有了一个实例,不必像上面描述的那样担心种族问题。随着Properties
类扩展Hashtable
这在技术上应该是可行的,尽管Properties
实际上并不适用于那些不是String
s的值,使用一个现代的线程安全Map
实现,例如ConcurrentHashMap
,会更好:
public void tSafe(List<Foo> list, Properties status) {
if(list == null) return;
String key = "COUNT";
AtomicInteger a = new AtomicInteger(Integer.valueOf(status.getProperty(key,"0")));
list.parallelStream().filter(Foo::check).
forEach(foo -> {status.setProperty(key, String.valueOf(a.incrementAndGet())); }
);
}
private interface Foo {
public boolean check();
}
public void tSafe(列表、ConcurrentMap状态){
if(list==null){
返回;
}
String key=“COUNT”;
putIfAbsent状态(键,新原子整数(0));
list.parallelStream()
.filter(Foo::check)
.forEach(foo->{status.get(ket).incrementAndGet();});
}
So。。我是否需要将AtomicInteger作为静态最终变量,而不是将其用作局部变量?使用Atomic*实现线程安全的最佳实践是什么?@aravindpogu我试图描述一种更好的方法(当然是IMHO)——请参阅我编辑的答案。需要键作为第一个参数,然后是值:status.putIfAbsent(ket,new-AtomicInteger(0))代码>愚蠢的遗漏。。。不幸的是,我打字的速度比我想象的要快得多:-(.谢谢你注意到@Ferrybig(当然是经过编辑和修复的).@aravindpogu,变量与对象不是一回事。如果两个或多个线程共享一个AtomicInteger
对象,那么线程访问该对象所使用的变量类型或变量数量都无关紧要。线程安全性并不是指围绕多线程构造的问题生产线安全。
public void tSafe(List<Foo> list, ConcurrentMap<String, AtomicInteger> status) {
if(list == null) {
return;
}
String key = "COUNT";
status.putIfAbsent(key, new AtomicInteger(0));
list.parallelStream()
.filter(Foo::check)
.forEach(foo -> { status.get(ket).incrementAndGet(); });
}