(计数器)CountDownLatch

CountDownLatch 类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。

代码实战:

首先写了一个枚举类,便于下面的举例

package com.bestqiang.thread.JUC;

/** * @author BestQiang */
public enum SeasonEnum {
    spring(1,"春"),summer(2,"夏"),autumn(3,"秋"),winter(4,"冬");

    private Integer index;
    private String season;

    SeasonEnum(Integer index, String season) {
        this.index = index;
        this.season = season;
    }

    public static SeasonEnum forEach_SeasonEnum(int index) {
        SeasonEnum[] values = SeasonEnum.values();
        for (SeasonEnum value : values) {
            if(index == value.index) {
                return value;
            }
        }
        return null;
    }

    public Integer getIndex() {
        return index;
    }

    public void setIndex(Integer index) {
        this.index = index;
    }

    public String getSeason() {
        return season;
    }

    public void setSeason(String season) {
        this.season = season;
    }
}

CountDownLatch的实战:

package com.bestqiang.thread.JUC;

import java.util.concurrent.CountDownLatch;

/** * @author BestQiang */
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(4);

        for(int i = 1; i <= 4; i ++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "\t 天,来了");
                countDownLatch.countDown();
            }, SeasonEnum.forEach_SeasonEnum(i).getSeason()).start();
        }
        countDownLatch.await();
        // 等到倒计时为0的时候,开始执行下面的语句
        System.out.println("朱自清的脚步近了!");
    }
}

运行结果:

"C:\Program Files\java\jdk1.8.0_101\bin\java.exe" -javaagent:D:\JetBrains\apps\IDEA-U\ch-0\191.6707.61\lib\idea_rt.jar=54728:D:\JetBrains\apps\IDEA-U\ch-0\191.6707.61\bin -Dfile.encoding=UTF-8 -classpath "C:\Program Files\java\jdk1.8.0_101\jre\lib\charsets.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\deploy.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\access-bridge-64.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\cldrdata.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\dnsns.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\jaccess.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\jfxrt.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\localedata.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\nashorn.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\sunec.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\sunjce_provider.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\sunmscapi.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\sunpkcs11.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\zipfs.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\javaws.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\jce.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\jfr.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\jfxswt.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\jsse.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\management-agent.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\plugin.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\resources.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\rt.jar;D:\workspace_idea\multithreading\out\production\threadPools" com.bestqiang.thread.JUC.CountDownLatchDemo
夏	 天,来了
冬	 天,来了
春	 天,来了
秋	 天,来了
朱自清的脚步近了!

(屏障)CyclicBarrier

CyclicBarrier 初始化时规定一个数目,然后计算调用了CyclicBarrier.await() 进入等待的线程数。当线程数达到了这个数目时,所有进入等待状态的线程被唤醒并继续。
CyclicBarrier 就象它名字的意思一样,可看成是个障碍, 所有的线程必须到齐后才能一起通过这个障碍。
CyclicBarrier 初始时还可带一个Runnable 的参数, 此Runnable 任务在CyclicBarrier 的数目达到后,所有其它线程被唤醒前被执行。

代码实战:

package com.bestqiang.thread.JUC;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/** * @author BestQiang */
public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            // 等到CyclicBarrier.await()的线程数达到7的时候,开始执行下面的语句
            System.out.println( "开始召唤神龙!");
        });
        for(int i = 1; i <= 7; i ++) {
            int f = i;
            int r = new Random().nextInt(4);
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "\t 收集到第:" + f + "龙珠");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, SeasonEnum.forEach_SeasonEnum(r == 0 ? 1 : r).getSeason()).start();
        }
    }
}

"C:\Program Files\java\jdk1.8.0_101\bin\java.exe" -javaagent:D:\JetBrains\apps\IDEA-U\ch-0\191.6707.61\lib\idea_rt.jar=55089:D:\JetBrains\apps\IDEA-U\ch-0\191.6707.61\bin -Dfile.encoding=UTF-8 -classpath "C:\Program Files\java\jdk1.8.0_101\jre\lib\charsets.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\deploy.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\access-bridge-64.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\cldrdata.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\dnsns.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\jaccess.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\jfxrt.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\localedata.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\nashorn.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\sunec.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\sunjce_provider.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\sunmscapi.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\sunpkcs11.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\zipfs.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\javaws.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\jce.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\jfr.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\jfxswt.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\jsse.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\management-agent.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\plugin.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\resources.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\rt.jar;D:\workspace_idea\multithreading\out\production\threadPools" com.bestqiang.thread.JUC.CyclicBarrierDemo
春	 收集到第:1龙珠
夏	 收集到第:3龙珠
春	 收集到第:2龙珠
春	 收集到第:4龙珠
秋	 收集到第:5龙珠
夏	 收集到第:6龙珠
春	 收集到第:7龙珠
开始召唤神龙!

Process finished with exit code 0

(计数信号量)Semaphore

Semaphore 是一种基于计数的信号量。它可以设定一个阈值,基于此,多个线程竞争获取许可信号,做自己的申请后归还,超过阈值后,线程申请许可信号将会被阻塞。Semaphore 可以用来构建一些对象池,资源池之类的,比如数据库连接池,我们也可以创建计数为1的Semaphore,将其作为一种类似互斥锁的机制,这也叫二元信号量,表示两种互斥状态。它的用法如下:
availablePermits函数用来获取当前可用的资源数量
semaphore.acquire(); //申请资源
semaphore.release();// 释放资源

package com.bestqiang.thread.JUC;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/** * @author BestQiang * 抢车位 */
public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);// 模拟三个车位
        for( int i = 1; i <= 7; i++) { // 模拟6部汽车
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "\t 抢到车位");
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println("\t" + "停车3秒后离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();
                }

            }, String.valueOf(i)).start();
        }
    }
}

"C:\Program Files\java\jdk1.8.0_101\bin\java.exe" -javaagent:D:\JetBrains\apps\IDEA-U\ch-0\191.6707.61\lib\idea_rt.jar=55756:D:\JetBrains\apps\IDEA-U\ch-0\191.6707.61\bin -Dfile.encoding=UTF-8 -classpath "C:\Program Files\java\jdk1.8.0_101\jre\lib\charsets.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\deploy.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\access-bridge-64.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\cldrdata.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\dnsns.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\jaccess.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\jfxrt.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\localedata.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\nashorn.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\sunec.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\sunjce_provider.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\sunmscapi.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\sunpkcs11.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\ext\zipfs.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\javaws.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\jce.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\jfr.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\jfxswt.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\jsse.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\management-agent.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\plugin.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\resources.jar;C:\Program Files\java\jdk1.8.0_101\jre\lib\rt.jar;D:\workspace_idea\multithreading\out\production\threadPools" com.bestqiang.thread.JUC.SemaphoreDemo
1	 抢到车位
4	 抢到车位
2	 抢到车位
	停车3秒后离开车位
	停车3秒后离开车位
	停车3秒后离开车位
5	 抢到车位
3	 抢到车位
6	 抢到车位
	停车3秒后离开车位
	停车3秒后离开车位
7	 抢到车位
	停车3秒后离开车位
	停车3秒后离开车位

Process finished with exit code 0

小总结:CountDownLatch为倒计数,CyclicBarrier为正计数,Semaphore为抢车位。