java并发编程(juc工具篇)

187 阅读2分钟

AtomicInteger

  • 基本类型:AtomicInteger

    private static final AtomicInteger count = new AtomicInteger(0);
    
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10000; j++) {
                count.incrementAndGet();
            }
        }
        Thread.sleep(3000);
        System.out.println(count.get());
    }
    
  • 数组类型:AtomicIntegerArray

    private static final int[] arr = new int[]{0, 5, 7};
    private static final AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(arr);
    
    public static void main(String[] args) throws InterruptedException {
        atomicIntegerArray.addAndGet(0, 100); // 索引0加100
        System.out.println(atomicIntegerArray.get(0));
    
        atomicIntegerArray.set(1, -66);  // 索引1设置为-66
        System.out.println(atomicIntegerArray.get(1));
    }
    
  • 引用类型:AtomicReference

    public static void main(String[] args) throws InterruptedException {
        Person user1 = new Person("张三", 23);
        Person user2 = new Person("李四", 25);
        Person user3 = new Person("王五", 20);
    
        //初始化为 user1
        AtomicReference<Person> atomicReference = new AtomicReference<>();
        atomicReference.set(user1); // reference --> user1
    
        //把 user2 赋给 atomicReference
        atomicReference.compareAndSet(user1, user2); // reference --> user2
        System.out.println(atomicReference.get());
    
        //把 user3 赋给 atomicReference
        atomicReference.compareAndSet(user1, user3);  // 失败, reference --> user2
        System.out.println(atomicReference.get());
    }
    

ReentrantLock

  • 一般用途:加锁

  • ReentrantLock内部维护了一个state变量和两个等待队列,通过CAS修改state来争抢锁,抢不到锁进入“同步队列”,条件不满足进入“等待队列”等待被唤醒,同步队列是个双向链表,等待队列是个单向链表

  • 加锁操作一定要放在 try 代码之前,避免未加锁成功又释放锁造成异常;

  • 释放锁一定要放在 finally 中,否则线程可能会阻塞

    private final Lock lock = new ReentrantLock();
    
    public void foo()
    {
        lock.lock(); // 阻塞等待
        try {
           // ... 执行一些操作 ... 
        } finally{
           lock.unlock();
        }
    }
    
    // 尝试获取锁(非阻塞)
    if (lock.tryLock(100, TimeUnit.MILLISECONDS)) {  
        try {  
            // ... 执行一些操作 ...  
        } finally {  
            lock.unlock();  
        }  
    } else {  
        // 超时后仍未获取到锁,执行备选逻辑  
    }  
    

ReentrantLock.png

CountDownLatch

  • 一般用途:等多个线程都执行完再执行

  • CountDownLatch内部维护一个计数器,每完成一个任务调用countDown()将计数器减1,当计数器的值为0时,主线程才会从调用await()方法的地方继续执行

  • CountDownLatch中的计数器是几,则要调用countDown几次,不然会一直等着计数器的值变为0,要在finally中执行减1操作

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3); // 计数器为3,表示需要等待3个任务完成
    
        // 启动 3 个线程来执行任务
        for (int i = 1; i <= 3; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " 执行任务");
                } finally {
                    latch.countDown();  // 每个线程执行完任务后递减计数器
                }
            }).start();
        }
    
        latch.await();  // 主线程等待所有任务完成
        System.out.println("继续执行主线程");
    }
    

CompletableFuture

  • 一般用途:创建异步操作、等所有任务都执行完成再接着执行

  • 创建异步操作

    • runAsync:没有返回值
    • supplyAsync:有返回值
    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
        System.out.println("无返回值...");
    });
    
    CompletableFuture.supplyAsync(() -> { int a = 10/0; return 666; }, executor)
    .exceptionally(ex -> {
         System.out.printf("异常:"+ex.toString());
         return -1;
    })
    .thenAccept(res -> {
        System.out.printf("返回值:" + res);
    });
    

相关文章