Java多线程(八)——多线程辅助功能类

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xcymorningsun/article/details/88019218

目录

一、引言

二、Semaphore

三、countdownlatch

四、cyclicbarrier

五、exchanger

六、总结


一、引言

在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier、Semaphore和exchanger。

Semaphore:一个计数信号量
CountDownLatch:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。 
CyclicBarrier:一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 
Exchanger:方便了两个共同操作线程之间的双向交换

下面举例子分别介绍这些类的使用场景

二、Semaphore

Semaphore 信号量对象管理的信号就像令牌,构造时传入个数,总数就是控制并发的数量。我们需要控制并发的代码,执行前先获取信号(通过acquire获取信号许可),执行后归还信号(通过release归还信号许可)。每次acquire成功返回后,Semaphore可用的信号量就会减少一个,如果没有可用的信号,acquire调用就会阻塞,等待有release调用释放信号后,acquire才会得到信号并返回。

如果Semaphore管理的信号量为1个,那么就退化到互斥锁了;如果多于一个信号量,则主要用于控制并发数。与通过控制线程数来控制并发数的方式相比,通过Semaphore来控制并发数可以控制得更加细粒度,因为真正被控制最大并发的代码放到acquire和release之间就行了。

使用场景,食堂做饭只有四个切菜刀,有十个人要切十个菜,限制菜刀数量抢到的先切菜,切完再给别人。

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

        for (int i=0;i<7;i++)
        {
            new Thread(new Runnable() {
                public void run() {
                    try {
                        semaphore.acquire();
                        System.out.println(Thread.currentThread().getName()+"获取到许可");
                        Thread.sleep(1000);
                        semaphore.release();

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


    }

}

输出结果:

Thread-0获取到许可
Thread-2获取到许可
Thread-1获取到许可
Thread-3获取到许可
Thread-4获取到许可
Thread-5获取到许可
Thread-6获取到许可

三、countdownlatch

一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。 

其机制是:当多个(具体数量等于初始化CountDownLatch时的count参数的值)线程都达到了预期状态或完成预期工作时触发事件,其他线程可以等待这个事件来触发自己的后续工作。这里需要注意的是,等待的线程可以是多个,即CountDownLatch是可以唤醒多个等待的线程的。达到自己预期状态的线程会调用CountDownLatch的countDown方法,而等待的线程会调用CountDownLatch的await方法。

CountDownLatch 很适合用来将一个任务分为n个独立的部分,等这些部分都完成后继续接下来的任务,CountDownLatch 只能出发一次,计数值不能被重置。

public class Testcutdownlatch {
    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(3);


        new Thread(new Runnable() {
            public void run() {
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("Waiter Released");
            }
        }).start();
        new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(1000);
                    latch.countDown();
                    Thread.sleep(1000);
                    latch.countDown();
                    Thread.sleep(1000);
                    latch.countDown();

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

            }
        }).start();

    }

}

输出结果:

Waiter Released

四、cyclicbarrier

可以协同多个线程,让多个线程在这个屏障前等待,直到所有线程都达到了这个屏障时,再一起继续执行后面的动作。

CyclicBarrier适用于多个线程有固定的多步需要执行,线程间互相等待,当都执行完了,再一起执行下一步。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier

public class Testcyclicbarrier {
    public static void main(String[] args) {

        final CyclicBarrier barrier1 = new CyclicBarrier(2, new Runnable() {
            public void run() {
                System.out.println("BarrierAction 1 executed ");
            }
        });
        final CyclicBarrier barrier2 = new CyclicBarrier(2, new Runnable() {
            public void run() {
                System.out.println("BarrierAction 2 executed ");

            }
        });
        for (int i=0;i<3;i++)
        {
            new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName()+"waited barrier1");
                        barrier1.await();
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName()+"waited barrier2");
                        barrier2.await();

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


    }

}

输出结果:

Thread-0waited barrier1
Thread-2waited barrier1
Thread-1waited barrier1
BarrierAction 1 executed 
Thread-0waited barrier2
Thread-1waited barrier2
BarrierAction 2 executed 

注意比较CountDownLatchCyclicBarrier

  (01) CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。

  (02) CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。

CountDownLatch 适用于一组线程和另一个主线程之间的工作协作。一个主线程等待一组工作线程的任务完毕才继续它的执行是使用 CountDownLatch 的主要场景;CyclicBarrier 用于一组或几组线程,比如一组线程需要在一个时间点上达成一致,例如同时开始一个工作。

五、exchanger

Exchanger 类方便了两个共同操作线程之间的双向交换;这样,就像具有计数为 2 的 CyclicBarrier,并且两个线程在都到达屏障时可以“交换”一些状态。(Exchanger 模式有时也称为聚集。)

Exchanger 通常用于一个线程填充缓冲(通过读取 socket),而另一个线程清空缓冲(通过处理从 socket 收到的命令)的情况。当两个线程在屏障处集合时,它们交换缓冲。

public class Testexchanger {
    public static void main(String[]args){
        final Exchanger exchanger = new Exchanger();
        //Action action=new Action();


        new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(1000);
                    exchanger.exchange(Thread.currentThread().getName()+"data");
                    System.out.println(Thread.currentThread().getName()+"我交给你了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            public void run() {
                try {
                    exchanger.exchange(Thread.currentThread().getName()+"data");
                    System.out.println(Thread.currentThread().getName()+"我交给你了");

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

    }

}

输出结果:

Thread-0我交给你了
Thread-1我交给你了

六、总结

  • semaphore
  • countdownlatch
  • cyclicbarrier
  • exchanger

猜你喜欢

转载自blog.csdn.net/xcymorningsun/article/details/88019218