Atomic译为原子的,顾名思义,肯定跟线程安全有关系。
之前做项目遇到多个线程公用同一资源的问题,当时用的是synchronized。
如果不考虑线程安全,那么多个线程公用的资源,会相互干扰。
例如:
public class Try {
private static int count;
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
new Thread(new Runnable() {
public void run() {
Try.fun();
}
}).start();
}
System.out.println("count:" + count);
}
public static void fun() {
try {
TimeUnit.MILLISECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
}
由于线程不安全,最后输出count随机数字。这是由于count在内存中只有一份拷贝,在count还没有自加之前又被取走了。因此结果小于1000。
如果加上synchronized又会是怎样的结果呢。
public class Try {
private static int count;
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
new Thread(new Runnable() {
public void run() {
Try.fun();
}
}).start();
}
System.out.println("count:" + count);
}
public static void fun() {
try {
TimeUnit.MILLISECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (Try.class) {
count++;
}
}
}
最后的结果还是小于1000,TimeUnit.MILLISECONDS.sleep(5);睡眠了5毫秒。在所有的线程还没有完全执行完就打印出了结果。
又需要介绍CountDownLatch,他是一个计数器,可以等待倒数到0再执行下面的操作。
public class Try {
private static int count;
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(1000);
for (int i = 0; i < 1000; i++) {
new Thread(new Runnable() {
public void run() {
Try.fun();
latch.countDown();
}
}).start();
}
try {
latch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("count:" + count);
}
public static void fun() {
try {
TimeUnit.MILLISECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (Try.class) {
count++;
}
}
}
现在到这一步,结果就绝对不会有错了,必然是1000。
然而除了synchronized,还有一种轻量级的原子操作。AtomicXxx。这个已经封装好,当他取值或者改变值得时候都是原子操作。
它包含有:
AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference
AtomicIntegerArray,AtomicLongArray
AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater
AtomicMarkableReference,AtomicStampedReference,AtomicReferenceArray
还是上面那个例子:
public class Try {
private static AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(1000);
for (int i = 0; i < 1000; i++) {
new Thread(new Runnable() {
public void run() {
Try.fun();
latch.countDown();
}
}).start();
}
try {
latch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("count:" + count);
}
public static void fun() {
try {
TimeUnit.MILLISECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
count.getAndIncrement();
}
}