常见并发工具类(JDK 8 例子使用)

读《Java并发编程的艺术》笔记。

一、CountDownLatch

等待多线程完成的CountDownLatch,允许一个或多个线程等待其他线程完成操作。底层依赖AQS实现。

例子:

import java.util.concurrent.CountDownLatch;

/**
 * {@link CountDownLatch} 测试类
 * <p>
 *
 * @author hyl
 * @version v1.0: CountDownLatchTest.java, v 0.1 2020/10/6 8:33 $
 */
public class CountDownLatchTest {

    static final int THREAD_COUNT = 4;

    static CountDownLatch start = new CountDownLatch(1);

    static CountDownLatch end = new CountDownLatch(THREAD_COUNT);

    public static void main(String[] args) throws InterruptedException {

        Runnable runnable = () -> {
            System.out.println(Thread.currentThread()
                .getName() + ": start");
            try {
                start.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread()
                .getName() + ": end");
            end.countDown();
        };

        for (int i = 0; i < THREAD_COUNT; i++) {
            Thread thread = new Thread(runnable, "run-thread-" + i);
            thread.start();
        }

        start.countDown();
        end.await();
        System.out.println(Thread.currentThread()
            .getName() + ": final");
    }

}

执行结果:

run-thread-1: start
run-thread-3: start
run-thread-0: start
run-thread-2: start
run-thread-2: end
run-thread-3: end
run-thread-1: end
run-thread-0: end
main: final

二、CyclicBarrier

同步屏障CyclicBarrier,字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一个组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏蔽才会开门,所有被屏障拦截的线程才会继续运行。底层依赖ReentrantLock实现。

例子:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * {@link CyclicBarrier} 测试类
 * <p>
 *
 * @author hyl
 * @version v1.0: CyclicBarrierTest.java, v 0.1 2020/10/6 6:27 $
 */
public class CyclicBarrierTest {

    static CyclicBarrier c = new CyclicBarrier(2, () -> System.out.println("start:"));

    public static void main(String[] args) {
        new Thread(() -> {
            
            try {
                c.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(1);
        }).start();

        try {
            c.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println(2);
    }

}

执行结果:

start:
1
2

CountDownLatchCyclicBarrier 的区别

  • CountDownLatch 底层依赖AQS实现。CyclicBarrier 底层依赖ReentrantLock实现。
  • CountDownLatch 的计算器只能使用一次,而 CyclicBarrier 的计数器可以使用 reset()方法重置。
  • CyclicBarrier 还提供其他有用的方法,getNumberWaiting() 方法可以获得 CyclicBarrier 阻塞的线程数量,isBroken() 方法用来了解阻塞的线程是否被中断。

三、Semaphore

Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。底层依赖AQS实现,存在公平和非公平两种模式,类似ReentrantLock

例子:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * {@link java.util.concurrent.Semaphore }测试类
 * <p>
 *
 * @author hyl
 * @version v1.0: SemaphoreTest.java, v 0.1 2020/10/6 7:36 $
 */
public class SemaphoreTest {

    private static final int THREAD_COUNT = 30;

    private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);

    private static Semaphore s = new Semaphore(10);

    public static void main(String[] args) {

        for (int i = 0; i < THREAD_COUNT; i++) {
            threadPool.execute(() -> {
                try {
                    s.acquire();
                    // 随机产生休眠时间
                    int time = new Object().hashCode() >> 28;
                    time = time == 0 ? 1 : time;
                    System.out.println(Thread.currentThread()
                        .getName() + ": save data >> " + time);
                    try {
                        Thread.sleep(time * 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    s.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        threadPool.shutdown();

    }

}

执行结果:

pool-1-thread-2: save data >> 6
pool-1-thread-1: save data >> 1
pool-1-thread-3: save data >> 2
pool-1-thread-5: save data >> 6
pool-1-thread-4: save data >> 2
pool-1-thread-7: save data >> 1
pool-1-thread-6: save data >> 6
pool-1-thread-9: save data >> 5
pool-1-thread-8: save data >> 1
pool-1-thread-10: save data >> 1
pool-1-thread-11: save data >> 2
pool-1-thread-13: save data >> 6
pool-1-thread-14: save data >> 5
pool-1-thread-12: save data >> 2
pool-1-thread-15: save data >> 4
pool-1-thread-16: save data >> 5
pool-1-thread-17: save data >> 1
pool-1-thread-18: save data >> 7
pool-1-thread-19: save data >> 3
pool-1-thread-20: save data >> 1
pool-1-thread-22: save data >> 4
pool-1-thread-21: save data >> 1
pool-1-thread-23: save data >> 4
pool-1-thread-26: save data >> 7
pool-1-thread-24: save data >> 4
pool-1-thread-25: save data >> 3
pool-1-thread-27: save data >> 6
pool-1-thread-29: save data >> 6
pool-1-thread-28: save data >> 6
pool-1-thread-30: save data >> 3

四、Exchanger

线程间交互数据的 Exchanger(交换者),一个用于线程间协作的工具类。Exchanger 用于进行线程间的数据交换。它提供了一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过 exchange() 方法交换数据,如果第一个线程先执行 exchange() 方法,它会一直等待第二线程也执行 exchange() 方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程产生出来的数据传递给对方。

可用于遗传算法,用于校对工作

底层依赖 ThreadLocalUnsafe 实现。

例子:

import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * {@link java.util.concurrent.Exchanger} 测试类
 * <p>
 *
 * @author hyl
 * @version v1.0: ExchangerTest.java, v 0.1 2020/10/6 8:06 $
 */
public class ExchangerTest {

    private static final Exchanger<String> exgr = new Exchanger<>();

    private static ExecutorService threadPool = Executors.newFixedThreadPool(2);

    public static void main(String[] args) {

        threadPool.execute(() -> {
            String A = "银行流水A";
            try {
                String B = exgr.exchange(A);
                System.out.println(Thread.currentThread()
                    .getName() + ":A拿到了B录入的:" + B);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        threadPool.execute(() -> {
            String B = "银行流水B";
            try {

                String A = exgr.exchange(B);
                System.out.println(Thread.currentThread()
                    .getName() + ":A和B数据是否一致:" + A.equals(B) + ",A录入的是:" + A + ",B录入的是:" + B);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        threadPool.shutdown();

    }

}

执行结果:

pool-1-thread-1:A拿到了B录入的:银行流水B
pool-1-thread-2:A和B数据是否一致:false,A录入的是:银行流水A,B录入的是:银行流水B
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值