hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

Java多线程(十五):CountDownLatch,Semaphore,Exchanger,CyclicBarrier,Callable和Future

2019-11-18杂谈搜奇网26°c
A+ A-

CountDownLatch

CountDownLatch用来使一个线程或多个线程守候到其他线程完成。CountDownLatch有个初始值count,await要领会壅塞线程,直到经由过程countDown要领挪用使count削减为0才会实行await要领背面的代码。
示例代码
MyThread50_0是WorkThread,差别的线程休眠时候不一样。

public class MyThread50_0 extends Thread
{
    private CountDownLatch cdl;
    private int sleepSecond;

    public MyThread50_0(String name, CountDownLatch cdl, int sleepSecond)
    {
        super(name);
        this.cdl = cdl;
        this.sleepSecond = sleepSecond;
    }

    public void run()
    {
        try
        {
            System.out.println(this.getName() + "启动了,时候为" + new Date());
            Thread.sleep(sleepSecond * 1000);
            cdl.countDown();
            System.out.println(this.getName() + "实行完了,时候为" + new Date());
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}

MyThread50_1是DoneThread和main要领

public class MyThread50_1 extends Thread {
    private CountDownLatch cdl;

    public MyThread50_1(String name, CountDownLatch cdl)
    {
        super(name);
        this.cdl = cdl;
    }

    public void run()
    {
        try
        {
            System.out.println(this.getName() + "要守候了, 时候为" + new Date());
            cdl.await();
            System.out.println(this.getName() + "守候完了, 时候为" + new Date());
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        CountDownLatch cdl = new CountDownLatch(3);
        MyThread50_1 dt0 = new MyThread50_1("DoneThread1", cdl);
        MyThread50_1 dt1 = new MyThread50_1("DoneThread2", cdl);
        dt0.start();
        dt1.start();
        MyThread50_0 wt0 = new MyThread50_0("WorkThread1", cdl, 2);
        MyThread50_0 wt1 = new MyThread50_0("WorkThread2", cdl, 3);
        MyThread50_0 wt2 = new MyThread50_0("WorkThread3", cdl, 4);
        wt0.start();
        wt1.start();
        wt2.start();
    }
}

运转效果以下

DoneThread2要守候了, 时候为Sun Sep 22 21:37:57 CEST 2019
DoneThread1要守候了, 时候为Sun Sep 22 21:37:57 CEST 2019
WorkThread3启动了,时候为Sun Sep 22 21:37:57 CEST 2019
WorkThread2启动了,时候为Sun Sep 22 21:37:57 CEST 2019
WorkThread1启动了,时候为Sun Sep 22 21:37:57 CEST 2019
WorkThread1实行完了,时候为Sun Sep 22 21:37:59 CEST 2019
WorkThread2实行完了,时候为Sun Sep 22 21:38:00 CEST 2019
WorkThread3实行完了,时候为Sun Sep 22 21:38:01 CEST 2019
DoneThread2守候完了, 时候为Sun Sep 22 21:38:01 CEST 2019
DoneThread1守候完了, 时候为Sun Sep 22 21:38:01 CEST 2019

“DoneThreadX要守候了”和“WorkThreadX启动了”的递次是随机的。
“WorkThreadX实行完了“的递次根据1、2、3,因为我们的守候时候2、3、4秒。
待WorkThread3实行完了,才会实行await()以后的代码,DoneThreadX实行完了,一样该递次随机。
这是一种加强版的守候/关照模子,它能够完成多个事情线程完成使命后关照多个守候线程最先事情。
我们之前的守候/关照模子只能完成一个事情线程完成使命后关照一个守候线程或许一切守候线程最先事情。

Semaphore

Semaphore用来掌握并发数目,Semaphore组织函数传入permit(允许),一个permit相当于一个不可重入锁,acquire要领取得permit,relase要领送还permit。
代码示例以下

public class MyThread51 {
    public static void main(String[] args)
    {
        final Semaphore semaphore = new Semaphore(5);

        Runnable runnable = new Runnable()
        {
            public void run()
            {
                try
                {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "取得了permit,时候为" + new Date());
                    Thread.sleep(2000);
                    System.out.println(Thread.currentThread().getName() + "释放了permit,时候为" + new Date());

                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
                finally
                {
                    semaphore.release();
                }
            }
        };

        Thread[] threads = new Thread[10];
        for (int i = 0; i < threads.length; i++)
            threads[i] = new Thread(runnable);
        for (int i = 0; i < threads.length; i++)
            threads[i].start();
    }
}

运转效果以下

Thread-2取得了permit,时候为Sun Sep 29 21:47:05 CEST 2019
Thread-3取得了permit,时候为Sun Sep 29 21:47:05 CEST 2019
Thread-4取得了permit,时候为Sun Sep 29 21:47:05 CEST 2019
Thread-1取得了permit,时候为Sun Sep 29 21:47:05 CEST 2019
Thread-0取得了permit,时候为Sun Sep 29 21:47:05 CEST 2019
Thread-3释放了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-1释放了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-0释放了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-2释放了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-4释放了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-5取得了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-7取得了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-6取得了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-9取得了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-8取得了permit,时候为Sun Sep 29 21:47:07 CEST 2019
Thread-5释放了permit,时候为Sun Sep 29 21:47:09 CEST 2019
Thread-8释放了permit,时候为Sun Sep 29 21:47:09 CEST 2019
Thread-9释放了permit,时候为Sun Sep 29 21:47:09 CEST 2019
Thread-6释放了permit,时候为Sun Sep 29 21:47:09 CEST 2019
Thread-7释放了permit,时候为Sun Sep 29 21:47:09 CEST 2019

2,3,4,1,0先取得了permit,相差两秒释放了permit;
5,7,6,9,8取得了permit,相差两秒释放了permit;
因为我们设置的permit是5,一切只能有五个线程取得permit。

Exchanger

Exchanger用来交流两个线程中的数据
示例代码以下

public class MyThread52 extends Thread{
    private String str;
    private Exchanger<String> exchanger;
    private int sleepSecond;

    public MyThread52(String str, Exchanger<String> exchanger, int sleepSecond) {
        this.str = str;
        this.exchanger = exchanger;
        this.sleepSecond = sleepSecond;
    }

    public void run() {
        try {
            System.out.println(this.getName() + "启动, 原数据为" + str + ", 时候为" + new Date());
            Thread.sleep(sleepSecond * 1000);
            str = exchanger.exchange(str);
            System.out.println(this.getName() + "交流了数据, 交流后的数据为" + str + ", 时候为" + new Date());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<String>();
        MyThread52 et0 = new MyThread52("111", exchanger, 3);
        MyThread52 et1 = new MyThread52("222", exchanger, 2);

        et0.start();
        et1.start();
    }
}

运转效果以下

Thread-1启动, 原数据为222, 时候为Sun Sep 29 22:18:36 CEST 2019
Thread-0启动, 原数据为111, 时候为Sun Sep 29 22:18:36 CEST 2019
Thread-0交流了数据, 交流后的数据为222, 时候为Sun Sep 29 22:18:39 CEST 2019
Thread-1交流了数据, 交流后的数据为111, 时候为Sun Sep 29 22:18:39 CEST 2019

能够看到,数据发生了交流,时候差为最长时候3s。

CyclicBarrier

一组线程守候对方都到达barrier point,再实行接下来的行动,barrier point是轮回的,它能够重用。
示例代码以下

public class MyThread53 extends Thread{
    private CyclicBarrier cb;
    private int sleepSecond;

    public MyThread53(CyclicBarrier cb, int sleepSecond)
    {
        this.cb = cb;
        this.sleepSecond = sleepSecond;
    }

    public void run()
    {
        try
        {
            System.out.println(this.getName() + "运转了");
            System.out.println(this.getName() + "预备守候了, 时候为" + new Date());
            Thread.sleep(sleepSecond * 1000);

            cb.await();
            System.out.println(this.getName() + "完毕守候了, 时候为" + new Date());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }


    public static void main(String[] args)
    {
        Runnable runnable = new Runnable()
        {
            public void run()
            {
                System.out.println("CyclicBarrier的一切线程await()完毕了,我运转了, 时候为" + new Date());
            }
        };
        //须要守候三个线程await()后再实行runnable
        CyclicBarrier cb = new CyclicBarrier(3, runnable);
        MyThread53 cbt0 = new MyThread53(cb, 3);
        MyThread53 cbt1 = new MyThread53(cb, 6);
        MyThread53 cbt2 = new MyThread53(cb, 9);
        cbt0.start();
        cbt1.start();
        cbt2.start();
    }
}

运转效果以下

Thread-0运转了
Thread-1运转了
Thread-2运转了
Thread-1预备守候了, 时候为Mon Sep 30 23:02:11 CEST 2019
Thread-2预备守候了, 时候为Mon Sep 30 23:02:11 CEST 2019
Thread-0预备守候了, 时候为Mon Sep 30 23:02:11 CEST 2019
CyclicBarrier的一切线程await()完毕了,我运转了, 时候为Mon Sep 30 23:02:20 CEST 2019
Thread-2完毕守候了, 时候为Mon Sep 30 23:02:20 CEST 2019
Thread-0完毕守候了, 时候为Mon Sep 30 23:02:20 CEST 2019
Thread-1完毕守候了, 时候为Mon Sep 30 23:02:20 CEST 2019

Runnable线程在Thread-0,Thread-1,Thread-2 await()后运转,Runnable线程和三个线程的实行时候险些雷同。

Callable和Future

Callable
因为Runnable接口run()返回值是void范例,实行使命后没法返回效果。所以我们须要Callable接口,该接口的call()能够返回值。
Future
Future示意一个异步计算效果,Future供应了以下要领
get():猎取使命实行效果
cancel():中断使命
isDone():推断使命是不是实行完成
isCancelled():推断使命是不是被作废

示例代码以下

public class MyThread54 implements Callable<String> {
    public String call() throws Exception
    {
        System.out.println("进入CallableThread的call()要领, 最先睡觉, 睡觉时候为" + new Date());
        Thread.sleep(10000);
        return "是ss12";
    }

    public static void main(String[] args) throws Exception
    {
        ExecutorService es = Executors.newCachedThreadPool();
        MyThread54 ct = new MyThread54();
        Future<String> f = es.submit(ct);
        es.shutdown();

        Thread.sleep(5000);
        System.out.println("主线程守候5秒, 当前时候为" + new Date());

        String str = f.get();
        System.out.println("Future已拿到数据, str = " + str + ", 当前时候为" + new Date());
    }
}

运转效果以下

进入CallableThread的call()要领, 最先睡觉, 睡觉时候为Sun Nov 03 11:00:22 CET 2019
主线程守候5秒, 当前时候为Sun Nov 03 11:00:27 CET 2019
Future已拿到数据, str = 是ss12, 当前时候为Sun Nov 03 11:00:32 CET 2019

能够看到,Future在10s后拿到了返回效果。

  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
Java多线程(十五):CountDownLatch,Semaphore,Exchanger,CyclicBarrier,Callable和Future

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282193.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>