本文共 2267 字,大约阅读时间需要 7 分钟。
什么是原子操作类?
为什么我们需要使用原子操作类来进行数据操作?
下面用简单的代码来验证原子操作类的线程安全性:
public class Context { public static int addNumTest;//普通的int类型数据 public static AtomicInteger addNum = new AtomicInteger();//原子integer类型}
private static void testAddNumTest(){ new Thread(new Runnable() { @Override public void run() { for (int i=0;i<1000000;i++){ System.out.println("1: " + ++Context.addNumTest); } } }).start(); new Thread(new Runnable() { @Override public void run() { for (int i=0;i<1000000;i++){ System.out.println("2: " + ++Context.addNumTest); } } }).start(); new Thread(new Runnable() { @Override public void run() { for (int i=0;i<1000000;i++){ System.out.println("3: " + ++Context.addNumTest); } } }).start();}
private static void testAddNum(){ new Thread(new Runnable() { @Override public void run() { for (int i=0;i<1000000;i++){ System.out.println("1: " + Context.addNum.addAndGet(1)); } } }).start(); new Thread(new Runnable() { @Override public void run() { for (int i=0;i<1000000;i++){ System.out.println("2: " + Context.addNum.addAndGet(1)); } } }).start(); new Thread(new Runnable() { @Override public void run() { for (int i=0;i<1000000;i++){ System.out.println("3: " + Context.addNum.addAndGet(1)); } } }).start();}
这里我们分别创建三个线程同时对数据进行自加操作,每个线程中循环1000000次,我们期望得到的结果是3000000,然而我们实际运行会发现,使用int类型的结果每次都会少于3000000,这是因为其中有多个线程同时操作addNumTest的情况,例如A线程读取到的addNumTest为10,与此同时B线程也读取到addNumTest为10,那么它们都会将计算结果11赋值给addNumTest,然而实际上我们希望的是A线程在计算时,B线程应该等到A线程将计算结果赋值给addNumTest后再进行计算,显然使用AtomicInteger的程序则保证了这一点
这里我将循环次数设置得很大,因为发现循环次数少的话很难出现计算结果偏少的情况,个人猜想,这是因为多线程实际是利用获取CPU时间片来实现多个任务处理的,也就是说,对于一个CPU核心而言,只会有一个活动的线程,并不存在真正的线程并发,循环次数很少时,很短的时间即可处理完成,很难用到CPU的多个核心,所以就很少出现计算结果偏少的情况
转载地址:http://hvtlf.baihongyu.com/