美文网首页
并发编程之原子变量AtomicInteger详细解析

并发编程之原子变量AtomicInteger详细解析

作者: 攻城狮Chova | 来源:发表于2021-09-05 23:36 被阅读0次
原子变量

AtomicInteger基本概念

  • AtomicInteger:
    • 是一个提供原子操作的Integer类
    • 通过线程安全的方式操作加减
  • AtomicInteger使用场景: AtomicInteger提供原子操作来进行Integer的使用,适合高并发的场景

Integer与AtomicInteger的比较

  • 在使用Integer的时候,必须加上synchronized锁来保证出现并发线程同时访问的情况
public class IntegerSample {
    private static Integer count = 0;

    synchronized static void increment() {
        count++;
    }
}
  • AtomicInteger中不需要加锁,因为AtomicInteger是提供原子操作
public class AtomicIntegerSample {
    private static AtomicInteger count = new AtomicInteger(0);
        
    static void increment() {
        count.getAndIncrement();
    } 
}

AtomicInteger源码

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueoffset;

    static {
        try {
            valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception e) {
            throw new Error(ex);
        }
    }

    private volatile int value;

    ...
}
  • value:
    • 这里的value使用了volatile关键字
  • volatile作用: 使得多个线程可以共享变量
  • volatile的问题: 使用volatile将使得JVM优化失去作用,导致效率降低

AtomicInteger使用实例

  • 在多线程的情况下,使用AtomicInteger:
public class AtomicTest {
    static long randomTime() {
        return (long)(Math.random() * 1000);
    }

    public static void main(String args[]) {
        // 阻塞队列
        final BlockingQueue<File> queue = new LinkedBlockingQueue<File>(100);
        // 线程池
        final ExecutorService exec = Executors.newFixedThreadPool(5);
        final File root = new File("D:\\chova");
        // 完成标志
        final File exitFile = new File("");
        /*
         * 原子整型 AtomicInteger
         * AtomicInteger可以在并发的情况下达到原子化更新,避免使用了synchronized,而且性能非常高
         */
         // 读 个数
         final AtomicInteger rc = new AtomicInteger();
         // 写 个数
         final AtomicInteger wc = new AtomicInteger();
         // 读线程
         Runnable read = new Runnable() {
            public void run() {
                scanFile(root);
                scanFile(exitFile);
            }
    
            public void scanFile(File file) {
                if (file.isDirectory()) {
                    File[] files = file.listFiles(new FileFilter() {
                        public boolean accept(File pathname) {
                            return pathname.isDirectory || pathname.getPath().endsWith(".java");
                        }
                    });
                    for (File one : files) {
                        scanFile(one);
                    }
                } else {
                    try {
                        // 调用AtomicInteger的incrementAndGet(),以原子方式将当前值加1并返回新值
                        int index = rc.incrementAndGet();
                        System.out.println("Read:" + index + " " + file.getPath());
                        // 添加到阻塞队列
                        queue.put(file);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
         };
         // submit方法提交一个Runnable任务用于执行,并返回一个表示该任务的Future
         exec.submit(read);

        /*
         * 四个写线程
         */
         for (int index = 0; index < 4; index++) {
            // 写线程
            final int num = index;
            Runnable write = new Runnable() {
                String threadName = "Write" + num;

                public void run() {
                    while (true) {
                        try {
                            Thread.sleep(randomTime());
                            // 调用AtomicInteger的incrementAndGet(),以原子方式将当前值加1并返回新值
                            int index = wc.incrementAndGet();
                            // 获取并移除此队列的头部,必要时在元素变得可用之前一直保持等待
                            File file = queue.take();
                            /*
                             * 队列中已无对象
                             */
                             if (file = exitFile) {
                                // 再次添加exitFile标志,以便让其余线程正常退出
                                queue.put(exitFile);
                                break;
                             }
                             System.out.println(threadName + ":" + index + " " + file.getPath());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            exec.submit(write);
         }
        exec.shutdown();
    }
}

总结

  • AtomicInteger是在使用非阻塞算法时实现并发控制,在一些高并发的场景中非常适用

相关文章

网友评论

      本文标题:并发编程之原子变量AtomicInteger详细解析

      本文链接:https://www.haomeiwen.com/subject/bmgswltx.html