Can we use AtomicInteger as a local variable in a method and ensure thread safety?

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(); } 

Description:

In the above example, status is a common property and contains a key named COUNT. My goal is to increase the counter and return it to the properties in order to count the number of checks. Consider the tSafe method being called by multiple threads, am I getting the correct count at the end? Note that I used AtomicInteger a as a local variable.

+5
source share
2 answers

If you have only one thread, this will work, however, if you have several threads causing it, you have some operations that are thread safe. This will be great if each thread works with different list and status objects.

Since status is a thread safe collection, you can lock it and provided that list not changed in another thread, that would be.

In general, working with String as numbers in streaming safe mode is very difficult to get right. You are much better off making your stream of values, that is, AtomicInteger and never again.

0
source

No, this does not guarantee thread safety. Even if incrementAndGet() itself atomic, getting the value from the Properties object and setting it back is not.

Consider the following scenario:

  • Topic # 1 gets the value from the Properties object. For argument, let's say that this is "100".
  • Thread # 2 gets the value from the Properties object. Since nothing happened, this value is still "100".
  • Thread # 1 creates an AtomicInteger , increments it, and places "101" in the Properties object.
  • Thread # 2 does the same and puts "101" in the Properties object instead of the 102 you expected.

EDIT:
In a more productive note, the best approach would be to simply save AtomicInteger on your state map and increase it in place. Thus, you have one copy and you do not need to worry about racing, as described above. Since the Properties class extends Hashtable<Object, Object> , this should technically work, although Properties not really intended for values ​​that are not String s, and you would be much better off with a modern thread-safe Map , like ConcurrentHashMap :

 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(); }); } 
0
source

Source: https://habr.com/ru/post/1245062/


All Articles