• 多线程工具类:CountDownLatch、CyclicBarrier、Semaphore、LockSupport



    CountDownLatch

    假如有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以。
    比如你想要买套房子,但是呢你现在手上没有钱。你得等这个月工资发了、然后年终奖发了、然后朋友借你得钱还给你了、然后再给朋友借一部分才可以买,这种场景你就可以使用CountDownLatch。

    CountDownLatch是JDK为我们提供的一个计数器,它的操作是原子操作,同一时间只能有一个线程去操作这个它。

    我们先来看一下CountDownLatch的主要方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //构造方法,接收计数器的数量
    public CountDownLatch(int count)
    //持续等待计数器归零
    public void await()
    //最多等待unit时间单位内timeout时间
    public boolean await(long timeout, TimeUnit unit)
    //计数器减1
    public void countDown()
    //返回现在的计数器数量
    public long getCount()

    下面是CountDownLatch的基本使用示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class CountDownLatchDemo {
    public static CountDownLatch countDownLatch = new CountDownLatch(5);
    static class ThreadDemo extends Thread {
    @Override
    public void run() {
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getId() + "完成任务");
    countDownLatch.countDown();
    }
    }
    public static void main(String[] args) throws InterruptedException {
    for (int i = 0; i < 5; i++) {
    new ThreadDemo().start();
    }
    countDownLatch.await();
    System.out.println("全部完成任务");
    }
    }


    CyclicBarrier

    相比较于CountDownLatch,CyclicBarrier可以完成前者的全部功能,但是相比前者,它的功能更加的强大。
    CyclicBarrier翻译过来的中文名称叫循环栅栏,顾名思义它可以循环使用
    CyclicBarrier还可以接收一个Runnable对象,当栅栏循环一次技术后会执行一次Runnable

    我们来看一下CyclicBarrier的常用方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //构造方法,第一个参数为栅栏饿长度,第二个就是上方所说的Runnable对象
    public CyclicBarrier(int parties, Runnable barrierAction)
    public CyclicBarrier(int parties)
    //获取现在的数量
    public int getParties()
    //持续等待栅栏归零
    public int await()
    //最多等待unit时间单位内timeout时间
    public int await(long timeout, TimeUnit unit)

    下面是CyclicBarrier的基本使用示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public class CyclicBarrierDemo {
    public static CyclicBarrier cyclicBarrier = new CyclicBarrier(5,new FinallyThreadDemo());
    static class ThreadDemo extends Thread {
    @Override
    public void run() {
    try {
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getId() + "完成任务");
    cyclicBarrier.await();
    } catch (InterruptedException e) {
    e.printStackTrace();
    } catch (BrokenBarrierException e) {
    e.printStackTrace();
    }
    System.out.println("到达屏障点每个线程都会瞬时继续执行");
    }
    }
    static class FinallyThreadDemo extends Thread {
    @Override
    public void run() {
    System.out.println("所有任务已经完成之后单独执行的任务!");
    }
    }
    public static void main(String[] args) throws InterruptedException {
    for (int i = 0; i < 10; i++) {
    new ThreadDemo().start();
    }
    }
    }

    观察打印结果我们可以发现:
    当循环栅栏的任务执行完一轮以后,如果构造时传入了Runnable对象,则先执行Runnable对象,然后在瞬间释放所有任务的锁。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    14完成任务
    15完成任务
    16完成任务
    17完成任务
    18完成任务
    所有任务已经完成之后单独执行的任务!
    到达屏障点每个线程都会瞬时继续执行
    到达屏障点每个线程都会瞬时继续执行
    到达屏障点每个线程都会瞬时继续执行
    到达屏障点每个线程都会瞬时继续执行
    到达屏障点每个线程都会瞬时继续执行
    19完成任务
    20完成任务
    21完成任务
    22完成任务
    23完成任务
    所有任务已经完成之后单独执行的任务!
    到达屏障点每个线程都会瞬时继续执行
    到达屏障点每个线程都会瞬时继续执行
    到达屏障点每个线程都会瞬时继续执行
    到达屏障点每个线程都会瞬时继续执行
    到达屏障点每个线程都会瞬时继续执行


    Semaphore

    在 浅谈Java中的锁:Synchronized、重入锁、读写锁 一文中,我们了解了synch和读写锁,我们发现使用锁的时候一次只允许一条线程方法。那么有什么东西可以提供更强大的控制方法么?这个东西就是信号量。

    信号量提供的主要方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //创建具有给定许可数的信号量
    Semaphore(int permits):构造方法,创建
    //拿走1个许可
    void acquire()
    //拿走多个许可
    void acquire(int n)
    //释放一个许可
    void release()
    //释放n个许可
    void release(int n):
    //当前可用的许可数
    int availablePermits():

    下面来看使用示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public class SemaphoreThreadDemo {
    public static Semaphore semaphore = new Semaphore(5);

    static class ThreadDemo extends Thread {
    @Override
    public void run() {
    try {
    semaphore.acquire();
    System.out.println(Thread.currentThread().getId() + "号线程在"+System.currentTimeMillis()+"获取资源");
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }finally {
    semaphore.release();
    }
    }
    }

    public static void main(String[] args) throws InterruptedException {
    for (int i = 0; i < 30; i++) {
    new ThreadDemo().start();
    }
    }

    }


    LockSupport

    我们在 Hello,Thread 和 生产者消费者模型 两篇文章中使用过wait和notify实现了线程之间的协作,其实关于线程协作JDK还为我们提供了另外一个工具类LockSupport。

    使用LockSupport实现等待通知功能时还不需要获取锁哦

    先来看一下LockSupport的常用方法:

    1
    2
    3
    4
    // 禁用当前线程
    static void park()
    // 如果参数线程的不可用,则使其可用。
    static void unpark(Thread thread)

    来看一下示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    public class LockSupportThreadDemo {
    public static Thread thread;
    static class WaitThreadDemo extends Thread {
    @Override
    public void run() {
    System.out.println("WaitThread wait,time=" + System.currentTimeMillis());
    thread = Thread.currentThread();
    LockSupport.park();
    System.out.println("WaitThread end,time=" + System.currentTimeMillis());
    }
    }
    static class NotifyThreadDemo extends Thread {
    @Override
    public void run() {
    System.out.println("NotifyThread notify,time=" + System.currentTimeMillis());
    LockSupport.unpark(thread);
    try {
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("NotifyThread end,time=" + System.currentTimeMillis());
    }
    }
    public static void main(String[] args) {
    WaitThreadDemo waitThreadDemo = new WaitThreadDemo();
    NotifyThreadDemo notifyThreadDemo = new NotifyThreadDemo();
    waitThreadDemo.start();
    try {
    Thread.sleep(100);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    notifyThreadDemo.start();
    }
    }

     


  • 相关阅读:
    分布式计算框架——MapReduce
    Hadoop总结
    HBase原理总结
    LeetCode牛客148题
    LeetCode刷题[Python版]
    【Linux】netstat命令详解
    基于docker搭建Prometheus+Grafana监控(一)
    Zabbix笔记一:zabbix安装
    【Linux】vi/vim中如果替换
    【redis】Redis学习:redis测试注意点
  • 原文地址:https://www.cnblogs.com/zhixiang-org-cn/p/10633799.html
Copyright © 2020-2023  润新知