ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] # 简介 使用原子的方式更新数组里的某个元素,可以确保修改数组中数据的线程安全性。 * AtomicIntegerArray:整形数组原子操作类 * AtomicLongArray:长整形数组原子操作类 * AtomicReferenceArray :引用类型数组原子操作类 上面三个类提供的方法几乎相同,所以我们这里以 AtomicIntegerArray 为例子来介绍 # AtomicIntegerArray类常用方法 ~~~ public final int get(int i)//获取 index=i 位置元素的值 public final int getAndSet(int i, int newValue)//返回 index=i 位置的当前的值,并将其设置为新值:newValue public final int getAndIncrement(int i)//获取 index=i 位置元素的值,并让该位置的元素自增 public final int getAndDecrement(int i)//获取 index=i 位置元素的值,并让该位置的元素自减 public final int getAndAdd(int delta)//获取 index=i 位置元素的值,并加上预期的值 boolean compareAndSet(int expect, int update)//如果输入的数值等于预期值,则以原子方式将 index=i 位置的元素值设置为输入值(update) public final void lazySet(int i, int newValue)//最终 将index=i 位置的元素设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值 ~~~ # 示例 > 统计网站页面访问量,假设网站有10个页面,现在模拟100个人并行访问每个页面10次,然后将每个页面访问量输出,应该每个页面都是1000次,代码如下: ~~~ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerArray; public class AtomicExample7 { static AtomicIntegerArray pageRequest = new AtomicIntegerArray(new int[10]); //模拟访问一次 public static void request(int page) throws InterruptedException { //模拟耗时5毫秒 TimeUnit.MILLISECONDS.sleep(5); //pageCountIndex为pageCount数组的下标,表示页面对应数组中的位置 int pageCountIndex = page - 1; pageRequest.incrementAndGet(pageCountIndex); } public static void main(String[] args) throws InterruptedException { long starTime = System.currentTimeMillis(); int threadSize = 100; //100个形成一组 CountDownLatch countDownLatch = new CountDownLatch(threadSize); //开100个线程 for (int i = 0; i < threadSize; i++) { Thread thread = new Thread(() -> { try { //每个线程访问10页 for (int page = 1; page <= 10; page++) { //每页10次 for (int j = 0; j < 10; j++) { request(page); } } } catch (InterruptedException e) { e.printStackTrace(); } finally { //每次都减少一次 countDownLatch.countDown(); } }); thread.start(); } countDownLatch.await(); long endTime = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName() + ",耗时:" + (endTime - starTime)); for (int pageIndex = 0; pageIndex < 10; pageIndex++) { System.out.println("第" + (pageIndex + 1) + "个页面访问次数为" + pageRequest.get(pageIndex)); } } } ~~~ 说明: > 代码中将10个面的访问量放在了一个int类型的数组中,数组大小为10,然后通过`AtomicIntegerArray`来操作数组中的每个元素,可以确保操作数据的原子性,每次访问会调用`incrementAndGet`,**此方法需要传入数组的下标,然后对指定的元素做原子+1操作**。输出结果都是1000,可以看出对于数组中元素的并发修改是线程安全的。如果线程不安全,则部分数据可能会小于1000。