Java中的并发工具类

CountDownLatch

CountDownLatch主要提供的机制是当多个线程都到达了预期状态或完成预期工作时触发,其他线程可以等待这个事件来触发自己后续的工作。等待的线程可以是多个,即CountDownLatch可以唤醒多个等待的线程。到达自己预期状态的线程会调用CountDownLatch的countDown方法,等待的线程会调用CountDownLatch的await方法。

CountDownLatch工作原理相对简单,可以简单看成一个倒计数器,在构造方法中指定初始值,每次调用countDown()方法时将计数器减1,而await()会等待计数器变为0。

package com.wy.JUC;

import java.util.Date;
import java.util.concurrent.CountDownLatch;

/**
 * @author 沪旦铭
 * @date 2018/5/1 21:39
 */
public class CountDownLatchDemo {

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        int count = 3;
        CountDownLatch countDownLatch = new CountDownLatch(count);
        for(int i=0;i<count;i++){
            String threadName = "threadName"+i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(String.format("%s\t%s %s", new Date(), threadName, "started"));
                    try {
                        Thread.sleep(1000);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    countDownLatch.countDown();
                    System.out.println(String.format("%s\t%s %s", new Date(), threadName, "ended"));
                }
            }).start();

        }
        try {
            countDownLatch.await();
            //await方法会阻塞,直到计数器为0
            //当countdownLatch中三个线程都达到预期时才会向下执行

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //主线程等待所有3个线程都执行结束后才开始执行
        long stop = System.currentTimeMillis();
        System.out.println(String.format("Total time : %sms", (stop - start)));

    }
}

执行结果,注意:执行结果并不唯一,直到countDownLatch中的三个线程都达到预期状态,主线成就可以执行了。

Tue May 01 22:13:10 CST 2018    threadName1 started
Tue May 01 22:13:10 CST 2018    threadName0 started
Tue May 01 22:13:10 CST 2018    threadName2 started
Tue May 01 22:13:11 CST 2018    threadName0 ended
Tue May 01 22:13:11 CST 2018    threadName1 ended
Total time : 1085ms
Tue May 01 22:13:11 CST 2018    threadName2 ended

CyclicBarrierDemo

CyclicBarrier,从字面上理解是指循环屏障。CyclicBarrier可以协同多个线程,让多个线程在这个屏障前等待,直到所有线程都到达这个屏障时,再一起继续执行后面的动作。任何一个线程执行到await()方法时就会进入阻塞等待状态,直到所有线程都到达await()  时所有线程才会同时从await()  返回,继续后面的工作。如果在构造CyclicBarrier时设置一个Runnable实现,那么最后一个线程到达await() ,那么就可以执行Runnable中的方法。CyclicBarrier有一个reset方法可以让CyclicBarrier循环使用。

CyclicBarrier两个构造方法:

CyclicBarrier(int parties)

CyclicBarrier(int parties, Runnable barrierAction)

package com.wy.JUC;

import java.util.Date;
import java.util.concurrent.CyclicBarrier;

/**
 * @author 沪旦铭
 * @date 2018/5/1 22:15
 */
public class CyclicBarrierDemo {

    public static void main(String[] args) {
        int count = 3;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(count);
        for(int i=0;i<count;i++){
            String threadName = "threadName"+i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(String.format("%s\t%s %s", new Date(), threadName, " is waiting"));
                    try {
                        cyclicBarrier.await();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    System.out.println(String.format("%s\t%s %s", new Date(), threadName, "ended"));
                }
            }).start();
        }
    }
}

执行结果,注意,结果不一定每次都一样

Tue May 01 22:51:46 CST 2018    threadName0  is waiting
Tue May 01 22:51:46 CST 2018    threadName1  is waiting
Tue May 01 22:51:46 CST 2018    threadName2  is waiting
Tue May 01 22:51:46 CST 2018    threadName2 ended
Tue May 01 22:51:46 CST 2018    threadName0 ended
Tue May 01 22:51:46 CST 2018    threadName1 ended

CountDownLatch与CyclicBarrier区别

CountDownLatch和CyclicBarrier都是用于多个线程间协调。两者主要有两个区别:

  1. CountDownLatch是在多个线程都进行了countDown  方法后才会触发事件,执行countDown  方法后的线程

依然可以做自己线程的事情。CyclicBarrier是所有线程都到达await  方法才能继续做自己线程的事情。

  1. CountDownLatch不可以循环使用CyclicBarrier可以循环使用。

Semaphore

Semaphore是信号量的意思。用于控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用公共资源。

Semaphore可以用于流量控制。

package com.wy.JUC;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @author 沪旦铭
 * @date 2018/5/1 22:55
 */
public class SemaphoreDemo {

    private static final int ThreadCount = 30;//线程数量30个
    //构建含有30个线程的线程池
    private static ExecutorService threadPool = Executors.newFixedThreadPool(ThreadCount);
    //用于控制访问,最多允许10个线程访问
    private static Semaphore semaphore = new Semaphore(10);

    public static void main(String[] args) {

        for(int i=0;i<ThreadCount;i++){
            String threadName = "threadName"+i;
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();//获取许可
                        System.out.println(threadName);
                        Thread.sleep(1000);

                        semaphore.release();//释放许可
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}

执行结果,注意,能明显的感觉到每次只能执行10个线程的停顿


threadName0
threadName1
threadName2
threadName3
threadName4
threadName5
threadName6
threadName7
threadName8
threadName9
threadName10
threadName11
threadName12
threadName13
threadName15
threadName14
threadName16
threadName17
threadName19
threadName20
threadName21
threadName22
threadName23
threadName24
threadName18
threadName25
threadName26
threadName27
threadName28
threadName29

Exchanger

Exchanger是交换者的意思。Exchanger用于线程间的数据交换。只能是2个线程,他不支持更多的线程之间互换数据。两个线程通过exchange方法交换数据,如果一个线程先执行exchange  ,那么这个线程会一直等待第二个线程也执行exchange  方法,当两个线程都达到同步点时,这两个线程就可以交换数据。如果两个线程有一个没有执行exchange  方法,则另一个线程会一直等待。

package com.wy.JUC;

import java.util.concurrent.Exchanger;

/**
 * @author 沪旦铭
 * @date 2018/5/1 23:21
 */
public class ExchangerDemo {

    private static final Exchanger<String> exchanger = new Exchanger<>();

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                String A = "我是A线程";
                try {
                    exchanger.exchange(A);
                    System.out.println("我会等待另一个线程也执行exchange方法后才会执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                String B = "我是B线程";
                try {
                    Thread.sleep(1000);
                    String str = exchanger.exchange(B);
                    //str的内容是   我是A线程
                    //可见线程B获取了线程A的数据
                    System.out.println(str);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

执行结果

我是A线程
我会等待另一个线程也执行exchange方法后才会执行

参考书籍《大型网站系统与Java中间件实践》,《Java并发编程的艺术》

参考网站 http://www.jasongj.com/java/thread_communication/

猜你喜欢

转载自blog.csdn.net/fmuma/article/details/80161080
今日推荐