我理解AtomicInteger和其他原子变量允许并发访问。在什么情况下通常使用这个类?
当前回答
AtomicInteger的主要用途是在多线程上下文中,并且需要在不使用synchronized的情况下对整数执行线程安全操作。基本类型int上的赋值和检索已经是原子的,但AtomicInteger附带的许多操作在int上不是原子的。
最简单的是getAndXXX或xXXAndGet。例如,getAndIncrement()是i++的原子等价物,它不是原子的,因为它实际上是三个操作的捷径:检索、加法和赋值。compareAndSet对于实现信号量、锁、锁存器等非常有用。
使用AtomicInteger比使用同步执行相同的操作更快,可读性更强。
一个简单的测试:
public synchronized int incrementNotAtomic() {
return notAtomic++;
}
public void performTestNotAtomic() {
final long start = System.currentTimeMillis();
for (int i = 0 ; i < NUM ; i++) {
incrementNotAtomic();
}
System.out.println("Not atomic: "+(System.currentTimeMillis() - start));
}
public void performTestAtomic() {
final long start = System.currentTimeMillis();
for (int i = 0 ; i < NUM ; i++) {
atomic.getAndIncrement();
}
System.out.println("Atomic: "+(System.currentTimeMillis() - start));
}
在我使用Java 1.6的PC上,原子测试在3秒内运行,而同步测试在5.5秒内运行。这里的问题是同步操作(notatomic++)非常短。所以同步的成本相对于操作来说是非常重要的。
除了原子性,AtomicInteger还可以作为一个可变版本的Integer,例如在map中作为值使用。
其他回答
Atomic classes are not general purpose replacements for java.lang.Integer and related classes. They do not define methods such as equals, hashCode and compareTo. (Because atomic variables are expected to be mutated, they are poor choices for hash table keys.) Additionally, classes are provided only for those types that are commonly useful in intended applications. For example, there is no atomic class for representing byte. In those infrequent cases where you would like to do so, you can use an AtomicInteger to hold byte values, and cast appropriately. You can also hold floats using Float.floatToRawIntBits(float) and Float.intBitsToFloat(int) conversions, and doubles using Double.doubleToRawLongBits(double) and Double.longBitsToDouble(long) conversions.
参考:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html
在Java 8中,原子类扩展了两个有趣的函数:
int getAndUpdate(IntUnaryOperator updateFunction) int updateAndGet(IntUnaryOperator updateFunction)
两者都使用updateFunction来执行原子值的更新。区别在于第一个返回旧值,第二个返回新值。updateFunction可以实现为执行比标准操作更复杂的“比较和设置”操作。例如,它可以检查原子计数器不低于零,通常它需要同步,这里的代码是无锁的:
public class Counter {
private final AtomicInteger number;
public Counter(int number) {
this.number = new AtomicInteger(number);
}
/** @return true if still can decrease */
public boolean dec() {
// updateAndGet(fn) executed atomically:
return number.updateAndGet(n -> (n > 0) ? n - 1 : n) > 0;
}
}
代码取自Java原子示例。
我使用AtomicInteger来解决就餐哲学家的问题。
在我的解决方案中,使用AtomicInteger实例来表示fork,每个哲学家需要两个。每个哲学家都被标识为一个整数,从1到5。当一个哲学家使用一个fork时,AtomicInteger保存哲学家的值,从1到5,否则该fork没有被使用,因此AtomicInteger的值为-1。
AtomicInteger允许在一个原子操作中检查一个fork是否空闲,value==-1,如果空闲则将其设置为fork的所有者。参见下面的代码。
AtomicInteger fork0 = neededForks[0];//neededForks is an array that holds the forks needed per Philosopher
AtomicInteger fork1 = neededForks[1];
while(true){
if (Hungry) {
//if fork is free (==-1) then grab it by denoting who took it
if (!fork0.compareAndSet(-1, p) || !fork1.compareAndSet(-1, p)) {
//at least one fork was not succesfully grabbed, release both and try again later
fork0.compareAndSet(p, -1);
fork1.compareAndSet(p, -1);
try {
synchronized (lock) {//sleep and get notified later when a philosopher puts down one fork
lock.wait();//try again later, goes back up the loop
}
} catch (InterruptedException e) {}
} else {
//sucessfully grabbed both forks
transition(fork_l_free_and_fork_r_free);
}
}
}
因为compareAndSet方法不阻塞,它应该增加吞吐量,完成更多的工作。正如你所知道的,Dining Philosophers问题是在需要对资源进行受控访问时使用的,即需要fork,就像一个进程需要资源来继续工作一样。
AtomicInteger有两个主要用途:
As an atomic counter (incrementAndGet(), etc) that can be used by many threads concurrently As a primitive that supports compare-and-swap instruction (compareAndSet()) to implement non-blocking algorithms. Here is an example of non-blocking random number generator from Brian Göetz's Java Concurrency In Practice: public class AtomicPseudoRandom extends PseudoRandom { private AtomicInteger seed; AtomicPseudoRandom(int seed) { this.seed = new AtomicInteger(seed); } public int nextInt(int n) { while (true) { int s = seed.get(); int nextSeed = calculateNext(s); if (seed.compareAndSet(s, nextSeed)) { int remainder = s % n; return remainder > 0 ? remainder : remainder + n; } } } ... } As you can see, it basically works almost the same way as incrementAndGet(), but performs arbitrary calculation (calculateNext()) instead of increment (and processes the result before return).
就像gabuzo说的,当我想通过引用传递一个整型时,有时我使用AtomicIntegers。它是一个内置类,具有特定于体系结构的代码,因此它比我可以快速编写的任何MutableInteger更容易,也可能更优化。也就是说,这感觉像是对课程的滥用。
推荐文章
- Intellij IDEA Java类在保存时不能自动编译
- 何时使用Mockito.verify()?
- 在maven中安装mvn到底做什么
- 不可变与不可修改的集合
- 如何在JSON中使用杰克逊更改字段名
- GSON -日期格式
- 如何从线程捕获异常
- 无法解析主机"<URL here>"没有与主机名关联的地址
- 如何在Java中打印二叉树图?
- String.format()在Java中格式化双重格式
- com.jcraft.jsch.JSchException: UnknownHostKey
- Java中的操作符重载
- 如何加速gwt编译器?
- 在Hibernate中重新连接分离对象的正确方法是什么?
- 应该……接住环内还是环外?