I have a class
@Component
public class JmxConf implements Serializable {
private static final long serialVersionUID = 5586922486161726170L;
private AtomicInteger count = new AtomicInteger(0);
public AtomicInteger getCount() {
return count;
}
}
And I autowired this class to another
@Component
public class QueueListener {
private ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
@Autowired
private JmxConf jmxConf;
public doIt(){
if(jmxConf.getCount().get()>.....) {
jmxConf.getCount().incrementAndget();
......
executor.submit(new thread here);
jmxConf.getCount().decrementAndget();
}
}
}
We have one singleton bean which has a state but access to this state is controlled by an atomic variable. Will this class be thread-safe? And if not, why. Thanks
No it won't be atomic. You have a race here:
if(jmxConf.getCount().get()>.....) {
jmxConf.getCount().incrementAndget();
Imagine the scenario where the greater than
is some number, just say 10.
if(jmxConf.getCount().get() > 10) {
jmxConf.getCount().incrementAndget();
What if, when the thread hits the if
the value is 9 . When it gets to the increment it was already incremented by another thread to 10 and now you increment it to a value of 11 .
You should use compareAndSet.
while(true){
int value = jmxConf.getCount().get() + 1;
if(value > 10){
break;
}
if(mxConfg.getCount().compareAndSet(value-1, value){
executor.submit(new thread here);
jmxConf.getCount().decrementAndGet();
break;
}
}
You can read more on atomic references and compareAndSet
offered by Java.
So why do we need the while(true)
? The compareAndSet function takes two parameters
public final boolean compareAndSet(int expect, int update)
The method says "Try to update the AtomicInteger in a thread safe matter, here is the value I expect it to be currently and here is the value I want to update it with. If, when trying to do the update, the value of the AtomicInteger is what I expect than you can safely do the update. If it's not what I expect it to be then don't update it and notify me that you didn't update it."
Let's say we enter the if
and the value is 5 if another thread is also trying to update the AtomicInteger with a value of 5 both threads will have an expectation of 5 as the parameter. Because it is thread-safe only one thread can win which means one will fail (the compareAndSet will return false on failure). In that case we should re-try the compareAndSet until we succeed or exceed the threshold in which we break
.
AtomicInteger是线程安全的,因此这将是线程安全的。
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.