Java并发编程的艺术笔记-Java中的并发工具类

1.CountDownLatch

  • CountDownLatch允许一个或多个线程等待其他线程完成操作

  • join方法:

    • join用于让当前执行线程等待join线程执行结束,原理是不停检查join线程是否存活,如果join线程存活则让当前线程永远等待
    while (isAlive()) {
        wait(0);
    }
    
    • 待join线程中止后,线程的this.notifyAll()方法会被调用(该方法是在JVM里实现的,JDK里看不到)
  • CountDownLatch的使用:

static CountDownLatch c = new CountDownLatch(2);  // 设置计数器的值为2
public static void main(String[] args) throws InterruptedException {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println(1);
            c.countDown();  // 计数器减1
            System.out.println(2);
            c.countDown();  // 计数器减1
        }
    }).start();
    c.await();  // 阻塞主线程,直到计数器的值为0
    System.out.println("3");
}

2.CyclicBarrier

  • 让一组线程到达一个屏障(也叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行(所有线程等待完成,然后一起做事情)

  • 每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞

static CyclicBarrier c = new CyclicBarrier(2);
public static void main(String[] args) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                ---业务代码-----
                // 插入一个屏障
                c.await();  // 等另一个线程准备好再继续往下执行
            } catch (Exception e) {
            }
            System.out.println(1);
        }
    }).start();
    try {
        ---业务代码-----
        // 插入一个屏障
        c.await();  // 等另一个线程准备好再继续往下执行(这里是主线程等待另一个线程)
    } catch (Exception e) {
    }
    System.out.println(2);
}
  • CyclicBarrier(int parties,Runnable barrierAction)用于在线程到达屏障时,优先执行barrierAction,方便处理更复杂的业务场景:
// 等代码中的第一个线程和线程A都执行完之后,才会继续执行主线程(输出3 1 2)
static CyclicBarrier c = new CyclicBarrier(2, new A());
public static void main(String[] args) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                c.await();  // 插入一个屏障
            } catch (Exception e) {
            }
            System.out.println(1);
        }
    }).start();
    try {
        c.await();  // 插入一个屏障
    } catch (Exception e) {
    }
    System.out.println(2);
}

static class A implements Runnable {
    @Override
    public void run() {
        System.out.println(3);
    }
}
  • CyclicBarrier和CountDownLatch的区别:
    • CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置(所以能处理更为复杂的业务场景)
    • CountDownLatch是一/多个线程(老师)等待另外N个线程完成某个事情之后才能执行(N个学生做完了试卷就可走,不用等待其他的学生完成);CyclicBarrier是N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待(一个游戏玩家加载到100%还不可以开局,须要等到其他N-1的游戏玩家都加载到100%才可以开局)

3.Semaphore

  • Semaphore(信号量)用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源

  • 用于做流量控制,特别是公用资源有限的应用场景

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) {
    // 虽然有30个线程在执行,但是只允许10个并发执行
    for (int i = 0; i< THREAD_COUNT; i++) {
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    s.acquire();  // 获取许可证
                    System.out.println("save data");
                    s.release();  // 归还许可证
                } catch (InterruptedException e) {
                }
            }
        });
    }
    threadPool.shutdown();
}

4.Exchanger

  • Exchanger(交换者)是用于线程间协作的工具类(进行线程间的数据交换)

  • 提供一个同步点,在这个同步点中两个线程可以交换彼此的数据

  • 如果第一个线程先执行exchange方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方

private static final Exchanger<String> exgr = new Exchanger<>();
private static ExecutorService threadPool = Executors.newFixedThreadPool(2);

public static void main(String[] args) {
    threadPool.execute(new Runnable() {
        @Override
        public void run() {
            try {
                String A = "银行流水1";  // A录入银行流水数据
                exgr.exchange(A);  // A表示需要和另个线程传递的数据
            } catch (InterruptedException e) {
            }
        }
    });
    threadPool.execute(new Runnable() {
        @Override
        public void run() {
            try {
                String B = "银行流水2";  // B录入银行流水数据
                String A = exgr.exchange(B);  // B表示需要和另个线程传递的数据,A表示从另个线程提供的数据
                System.out.println("A和B数据是否一致:" + A.equals(B) + ",A录入的是:" + A + ",B录入是:" + B);
            } catch (InterruptedException e) {
            }
        }
    });
    threadPool.shutdown();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值