带你快速搞定java多线程(5)

目录
  • 1、介绍
  • 2、countdownlantch的用法。
  • 3、如何利用AQS 实现 CountDownLatch
  • 4、总结

1、介绍

CountDownLantch 倒数计时器,一个同步辅助类,一个线程(或者多个),等待另外N个线程完成某个事情后才能执行。用给定的计数初始化CountDownLatch,其含义是要被等待执行完的线程个数。

每次调用CountDown(),计数减1,执行到await()函数会阻塞等待线程的执行,直到计数为0。

CountDownLantch 无法重置

2、countdownlantch的用法。

举个例子

场景:模拟10人赛跑。喊完“Game Start”才开始跑,10人跑完后才喊"Game Over.",代码如下:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* CountDownLatchTest
* @author 香菜
*/
public class CountDownLatchTest {
   private static final int RUNNER_COUNT = 10;
   private static final int CORE_THREAD_COUNT = 10;
   public static void main(String[] args) throws InterruptedException {
       final CountDownLatch begin = new CountDownLatch(1);
       final CountDownLatch end = new CountDownLatch(RUNNER_COUNT);
       final ExecutorService exec = Executors.newFixedThreadPool(CORE_THREAD_COUNT);
       // 启动是个线程
       for (int i = 0; i < RUNNER_COUNT; i++) {
           final int NO = i + 1;
           Runnable run = () -> {
               try {
                   // 主线程 begin 之后所有的线程才会开始运行
                   begin.await();
                   Thread.sleep((long)(Math.random() * 10000));
                   System.out.println("No." + NO + " arrived");
              } catch (InterruptedException e) {
                   e.printStackTrace();
              } finally {
                   // 当前线程结束
                   end.countDown();
              }
          };
           exec.submit(run);
      }
       System.out.println("Game Start ...");
       begin.countDown();
       // 等待其他的线程结束
       end.await();
       System.out.println("Game Over.");
       exec.shutdown();
  }
}

3、如何利用AQS 实现 CountDownLatch

  • void await():如果当前count大于0,当前线程将会wait,直到count等于0或者中断。
  • boolean await(long timeout, TimeUnit unit):使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。
  • void countDown():递减锁存器的计数,如果计数到达零,则释放所有等待的线程。 long getCount() :获得计数的数量

通过代码可见,CountDownLatch 的核心实现是内部类 Sync,Sync 继承自 AbstractQueuedSynchronizer,让我们打开Sync 一探究竟。

private static final class Sync extends AbstractQueuedSynchronizer {
      private static final long serialVersionUID = 4982264981922014374L;
      Sync(int count) {
          setState(count);
      }
      int getCount() {
          return getState();
      }
      protected int tryAcquireShared(int acquires) {
          return (getState() == 0) ? 1 : -1;
      }
      protected boolean tryReleaseShared(int releases) {
          // Decrement count; signal when transition to zero
          for (;;) {
              int c = getState();
              if (c == 0)
                  return false;
              int nextc = c-1;
              if (compareAndSetState(c, nextc))
                  return nextc == 0;
          }
      }
  }

整个Sync 的代码实现 很简单,

  • 线程计数 是通过 state 控制 ,上篇文章我们分析过,state的同步使用 CAS 实现的乐观锁。
  • 获得锁计数 通过 tryAcquireShared ,代码很直接了,如果state == 0 返回1,将当前线程加入到队列中
  • 释放锁 通过 tryReleaseShared 将 state -1 ,释放一个锁。

AQS的实现可以看下上篇文章。《多线程系列五》没人给你说的AQS,打通多线程编程

4、总结

通过分析 countdownlantch 单独的代码可以看到通过AQS 实现的线程同步是多么简单,所以理解了AQS 就可以实现自己的同步器。

本篇文章就到这里了,希望能对你有所帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 带你快速搞定java多线程(3)

    目录 一.锁的概念 二.synchronized 的使用方式 三.synchronized 的实现原理列 小结 四.线程池是什么 五.为什么要用线程池? 六.看下类图,从整体上理解下 七.线程池的创建 八.线程池核心参数说明 九.几个疑问点 9.1.是怎么保证线程不销毁的? 9.2 提交任务有哪几种方式? 9.3 拒绝策略都有哪些? 9.4 线程池的关闭 9.5 初始化线程池时线程数的选择 十.总结 一.锁的概念 先来聊聊这几个概念,总不能聊起来的时候啥也不知道,只知道干活也没有用. 公平锁:当

  • 带你快速搞定java多线程(4)

    目录 1.AQS 是什么? 2.AQS 模型 3.AQS state 4.AQS 两种资源共享方式: 5.模板方式实现自定义 6.锁的分类:公平锁和非公平锁,乐观锁和悲观锁 7.CAS 8.总结 1.AQS 是什么? AQS 是类 AbstractQueuedSynchronizer的简称,也是常用锁的基类,比如常见的ReentrantLock,Semaphore,CountDownLatch 等等. AQS提供了一种实现阻塞锁和一系列依赖FIFO等待队列的同步器的框架.是Java提供的一种模板

  • Java经典面试题汇总--多线程

    目录 1. 并行和并发有什么区别? 2. 线程和进程的区别? 3. 守护线程是什么? 4. 实现多线程的方式有哪些? 5. 说一下 runnable 和 callable 有什么区别? 6. sleep() 和 wait() 有什么区别? 7. 线程有哪些状态? 8. notify()和 notifyAll()有什么区别? 9. 线程的 run() 和 start() 有什么区别? 10. 创建线程池有哪几种方式? 11. 线程池中 submit() 和 execute() 方法有什么区别? 1

  • 带你快速搞定java多线程(2)

    目录 1.Future的类图结构,从整体上看下Future的结构 2.future的使用,说的再多都么什么用,来个例子悄悄怎么用的. 3.通俗理解 4.原理 5.总结 1.Future的类图结构,从整体上看下Future的结构 首先看下future接口的函数,共有5个方法. get() 获取执行的结果,另外一个重载是有时间限制的get ,如果超时会有异常 isDone() 判断future 结果是否处理完成 cancel 取消任务 2.future的使用,说的再多都么什么用,来个例子悄悄怎么用的

  • 带你快速搞定java多线程

    目录 1.什么是线程 2.线程的状态 3.怎么通俗理解进程,线程? 4.线程和进程的区别 5.什么是线程安全 6.如何创建线程 总结: 1.什么是线程 线程是操作系统调度的最小单元,也叫轻量级进程.它被包含在进程之中,是进程中的实际运作单位.同一进程可以创建多个线程,每个进程都有自己独立的一块内存空间.并且能够访问共享的内存变量. 2.线程的状态 线程的状态一般看到的也就是Runable 和blocked ,最多的还是blocked,因为cpu的时间片很短,切换的很快等待IO,等待临界资源.大概

  • 带你快速搞定java多线程(5)

    目录 1.介绍 2.countdownlantch的用法. 3.如何利用AQS 实现 CountDownLatch 4.总结 1.介绍 CountDownLantch 倒数计时器,一个同步辅助类,一个线程(或者多个),等待另外N个线程完成某个事情后才能执行.用给定的计数初始化CountDownLatch,其含义是要被等待执行完的线程个数. 每次调用CountDown(),计数减1,执行到await()函数会阻塞等待线程的执行,直到计数为0. CountDownLantch 无法重置 2.coun

  • 带你快速搞定java IO

    目录 一.IO底层是怎么回事? 二.梳理类的结构 三.IO类大点兵 四.来波实例展示 1.访问操作文件(FileInputStream/FileReader ,FileOutputStream/FileWriter) 2.缓存流的使用(BufferedInputStream/BufferedOutputStream,BufferedReader/BufferedWriter) 3.获取键盘输入 总结: 一.IO底层是怎么回事? 操作系统就是管家,电脑的设备就是资源,如果进程先要操作资源,必须要进

  • 带你快速搞定java并发库

    目录 一.总览 二.Executor总览 三.继承结构 四.怎么保证只有一个线程 五.怎么保证时间可以定时执行 六.使用 总结 一.总览 计算机程序 = 数据 + 算法. 并发编程的一切根本原因是为了保证数据的正确性,线程的效率性. Java并发库共分为四个大的部分,如下图 Executor 和 future 是为了保证线程的效率性 Lock 和数据结构 是为了维持数据的一致性. Java并发编程的时候,思考顺序为, 对自己的数据要么加锁.要么使用提供的数据结构,保证数据的安全性 调度线程的时候

  • 带你快速搞定java数组

    目录 1.数组的定义 2.array 遍历 3.List和array 之间的转换 1.数组转list 2.list 转数组 3.Arrays工具类 4.可能遇到的问题 总结 1.数组的定义 先声明后使用 数据类型 [] 数组名称 = new 数据类型[长度];String[] arr3 = new String[5]; 数据类型 数组名称[] = new 数据类型[长度];String arr[] = new String[5]; 直接初始化 String[] arrs = {"1",

  • 带你轻松搞定Java面向对象的编程--数组,集合框架

    目录 一.数组 1.数组的定义 2.数组的声明 3.数组的初始化 二.集合概述 三.Collection接口 1.Collection接口概述 2.集合框架的三个组件 3.Iterator接口 四.List接口 1.ArrayList类 2.LinkedList类 五.Set接口 1.HashSet类 六.Map接口 1.HashMap类 七.泛型 总结 一.数组 1.数组的定义 数组是为了解决同类数据整合摆放而提出的,可以理解为一组具有相同类型的变量的集合,它的每个元素都具有相同的数据类型.

  • 带你快速搞定Mysql优化

    目录 1.查询语句的执行顺序 2.数据类型的选择 3.索引优化 主键索引 多列索引 4.查询性能优化 1.查询的生命周期 2.SELECT语句尽量指明查询字段名称 3.小表驱动大表 总结 1.查询语句的执行顺序 select[distinct]   from   join(如left join)   on   where   group by   having   union   order by   limit 执行顺序: from where 聚 having order limit 1.f

随机推荐