在多线程的场景下,有些并发流程需要人为来控制,在JDK的并发包里提供了几个并发工具类:CountDownLatch、CyclicBarrier、Semaphore。

一、CountDownLatch

 import java.util.concurrent.CountDownLatch;

 public class CountDownLatchTest
{
    //设置N为2
static CountDownLatch c = new CountDownLatch(2);
public static void main(String[] args) throws Exception
{
Thread t1 = new Thread(new Runnable()
{ @Override
public void run()
{
System.out.println("1");
           //将N减1
c.countDown();
}
}); Thread t2 = new Thread(new Runnable()
{ @Override
public void run()
{
System.out.println("2");
c.countDown();
}
});
t1.start();
t2.start();
      //让当前线程等待,直到计数N为0
c.await();
System.out.println("3");
}
}

执行结果:

1
2
3

这里会存在两种结果:123或者213,但是绝对不会出现3打印在1、2前面的。

new CountDownLatch(2);

这个CountDownLatch的构造函数接收一个int类型的参数作为计数器,N表示阻塞的线程必须等待N次countDown才能执行。

每次调用CountDownLatch的countDown方法时,N就会减1,而这个方法可以使用在任何地方,这里的N点可以是N个线程,也可以是一个线程中N个步骤。

而CountDownLatch的await方法则会阻塞当前线程,直到N为0的时候才能执行。

我们将上面的程序改造下,让线程中有两个打印动作,并且第二个动作前线程休眠一段时间:

 import java.util.concurrent.CountDownLatch;

 public class CountDownLatchTest
{
static CountDownLatch c = new CountDownLatch(2);
public static void main(String[] args) throws Exception
{
Thread t1 = new Thread(new Runnable()
{ @Override
public void run()
{
System.out.println("1");
c.countDown();
try
{
Thread.sleep(500);
System.out.println("2");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}); Thread t2 = new Thread(new Runnable()
{ @Override
public void run()
{
System.out.println("3");
c.countDown();
}
});
t1.start();
t2.start();
c.await();
System.out.println("4");
}
}

执行结果:

1
3
4
2

这个结果是由于在打印完1、3之后,N已经变化为0,主线程执行打印4,由于线程1休眠,所以2最后才打印。

在上面的程序中,如果将N设置为3,则主线程中的打印4永远不会执行,因为没有N永远只会到1而不会减少到0.

在这里我们想起了线程的join方法,这个方法也是可以阻塞当前线程,等待某线程执行完成。通过对比,我们可以发现使用CountDownLatch这个工具类更灵活,因为countDown可以用在任何线程的任何地方。

CountDownLatch适合一个大任务拆分成多个小任务,然后在所有子任务完成后,通知其他的后续操作开始执行。

二、同步屏障CyclicBarrier

CyclicBarrier默认的构造方法CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达屏障,然后当前线程被阻塞,直到被拦截的线程全部都到达了屏障,然后前面被阻塞的线程才能开始执行,否则会被一直阻塞。

 public class CyclicBarrierTest
{
static CyclicBarrier c = new CyclicBarrier(3); public static void main(String[] args)
throws Throwable, BrokenBarrierException
{
Thread t1 = new Thread(new Runnable()
{
@Override
public void run()
{
try
{
c.await();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
catch (BrokenBarrierException e)
{
e.printStackTrace();
}
System.out.println("1"); }
});
Thread t2 = new Thread(new Runnable()
{
@Override
public void run()
{
try
{
c.await();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
catch (BrokenBarrierException e)
{
e.printStackTrace();
}
System.out.println("2");
}
}); t1.start();
t2.start();
c.await();
System.out.println("3");
}
}

执行结果:

3
1
2

上述中被屏障拦截的线程有3个,其中线程1和线程2执行的时候先到达屏障,然后被阻塞,主线程执行第52行到达屏障,至此阻塞的三个线程全部到达屏障,然后阻塞的线程可以去竞争CPU开始执行。

如果将拦截的线程数修改为4:

static CyclicBarrier c = new CyclicBarrier(4);

这样的话被拦截的线程数有4个,但是只有三个线程调用await方法告诉CyclicBarrier,我到达了屏障。所以这三个线程都会被阻塞。

另外还有一点就是CyclicBarrier的计数器可以重置,例如设置的是拦截线程数量为2,但是有3个线程调用了await()方法表示到达了屏障,这个时候会出现最先达到屏障的两个线程顺利执行完毕,而最后到达的第三个线程则一直被阻塞,因为它等不到另外一个线程到达屏障了。

而如果拦截线程的数量依旧为2,但是有4个线程调用了await()方法,那么这4个线程是分两批执行的,前两个线程满足拦截的线程数,到达屏障后放行;然后CyclicBarrier的计数器重置,后面两个线程到达屏障后放行。

 import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; import sun.java2d.SunGraphicsEnvironment.T1Filter; public class CyclicBarrierTest
{
static CyclicBarrier c = new CyclicBarrier(2); public static void main(String[] args) throws Throwable, BrokenBarrierException
{
Thread t1 = new Thread(new Runnable()
{
@Override
public void run()
{
try
{
c.await();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
catch (BrokenBarrierException e)
{
e.printStackTrace();
}
System.out.println("1"); }
});
Thread t2 = new Thread(new Runnable()
{
@Override
public void run()
{
try
{
c.await();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
catch (BrokenBarrierException e)
{
e.printStackTrace();
}
System.out.println("2");
}
}); Thread t3 = new Thread(new Runnable()
{
@Override
public void run()
{
try
{
c.await();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
catch (BrokenBarrierException e)
{
e.printStackTrace();
}
System.out.println("3"); }
});
t1.start();
t2.start();
t3.start();
c.await();
System.out.println("4");
}
}

CyclicBarrier可以用于多线程计算数据,最后合并结果的场景;由于CyclicBarrier的计数器可以重置,所以可以使用它处理更为复杂的业务场景,而CountDownLatch计数器只能使用一次。

三、信号量Semaphore

无论是内部锁synchronized还是重入锁ReentrantLock,一次都只允许一个线程访问某一个资源,而信号量却可以指定多个线程同时访问某一资源;主要用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。

 public class SemaphoreTest implements Runnable
{
final Semaphore s = new Semaphore(5);
@Override
public void run()
{
try
{
s.acquire();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " is done");
s.release();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
public class MainTest
{
public static void main(String[] args)
{
SemaphoreTest s = new SemaphoreTest();
//创建一个可重用固定线程数的线程池,线程数量为20
ExecutorService threadPool= Executors.newFixedThreadPool(20);
for(int i=0;i<20;i++)
{
threadPool.submit(s);
}
threadPool.shutdown();
}
}

执行的结果是每五个线程为一组打印消息。

线程池里面有20个可重复使用的线程数量,但是信号量只有5个,也就是每次只能并发5个线程执行,其他线程阻塞。

信号量为5,可以认为线程池里有5把锁,每个线程调用acquire和release分别表示获取锁和释放锁,这样,通过信号量就可以调度多个线程的执行。

并发工具类:CountDownLatch、CyclicBarrier、Semaphore的更多相关文章

  1. Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger

    在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...

  2. Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo

    Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo CountDownLatch countDownLatch这个类使一个线程等待其他线程 ...

  3. java 并发工具类CountDownLatch & CyclicBarrier

    一起在java1.5被引入的并发工具类还有CountDownLatch.CyclicBarrier.Semaphore.ConcurrentHashMap和BlockingQueue,它们都存在于ja ...

  4. 并发包下常见的同步工具类(CountDownLatch,CyclicBarrier,Semaphore)

    在实际开发中,碰上CPU密集且执行时间非常耗时的任务,通常我们会选择将该任务进行分割,以多线程方式同时执行若干个子任务,等这些子任务都执行完后再将所得的结果进行合并.这正是著名的map-reduce思 ...

  5. Java并发工具类 - CountDownLatch

    Java并发工具类 - CountDownLatch 1.简介 CountDownLatch是Java1.5之后引入的Java并发工具类,放在java.util.concurrent包下面 http: ...

  6. Java并发工具类CountDownLatch源码中的例子

    Java并发工具类CountDownLatch源码中的例子 实例一 原文描述 /** * <p><b>Sample usage:</b> Here is a pai ...

  7. Java中的并发工具类(CountDownLatch、CyclicBarrier、Semaphore、Exchanger)

    在JDK的并发包里提供了很多有意思的并发工具类.CountDownLatch.CyclicBarrier和Semaphore 工具类提供了一种并发流程控制的手段,Exchanger 工具类则提供了在线 ...

  8. 25.大白话说java并发工具类-CountDownLatch,CyclicBarrier,Semaphore,Exchanger

    1. 倒计时器CountDownLatch 在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种的业务场景下,通常可以使用Thread类的join ...

  9. java多线程10:并发工具类CountDownLatch、CyclicBarrier和Semaphore

    在JDK的并发包(java.util.concurrent下)中给开发者提供了几个非常有用的并发工具类,让用户不需要再去关心如何在并发场景下写出同时兼顾线程安全性与高效率的代码. 本文分别介绍Coun ...

  10. 多线程学习笔记六之并发工具类CountDownLatch和CyclicBarrier

    目录 简介 CountDownLatch 示例 实现分析 CountDownLatch与Thread.join() CyclicBarrier 实现分析 CountDownLatch和CyclicBa ...

随机推荐

  1. 【BZOJ1257】【CQOI2007】余数之和sum

    Description 给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的余数.例如j(5, ...

  2. hdu 1715 大菲波数 高精度和运算,水

    1.hdu 1715  大菲波数 2.链接:http://acm.hdu.edu.cn/showproblem.php?pid=1715 3.总结:水 #include<iostream> ...

  3. 内存和flash存储的区别

    http://bbs.21ic.com/icview-202550-1-1.html 一.内存 我们一般说的内存指的是DRAM,其主要特点是断电会丢失数据,可读写 二.ROM 断电不会丢失数据,数据只 ...

  4. android-数据存储之外部file存储(sdcard)

    一.基础概要 1.说明: 1>应用程序运行用到的数据文件可以保存到sd卡中 2>文件类型:任意 3>数据保存路径: 路径1:/storage/sdcard/Android/data/ ...

  5. Another app is currently holding the yum lock; waiting for it to exit...

    刚安装完虚拟机,用xshell连接上linux后,安装程序时一直出现这个信息Another app is currently holding the yum lock; waiting for it ...

  6. asp.net 与数据库操作

    <configuration> <system.web><compilation debug="true" targetFramework=" ...

  7. 通过Queue的构造函数的可选参数maxsize来设定队列长度

    创建一个"队列"对象 import Queuemyqueue = Queue.Queue(maxsize = 10) Queue.Queue类即是一个队列的同步实现.队列长度可为无 ...

  8. jQuery判断元素是否存在方法总结

    在jquery中判断元素是否存在我们可使用$("#div").length > 0)来判断了,意思就是判断元素长度了,如果没有肯定是不存在的哦,下面我来介绍介绍. 使用传统j ...

  9. requirejs解决异步模块加载方案

    他首先会遍历enableRegistry取出其中定义的模块,并且将没有加载成功的模块标识注入noLoads数组,如果过期了这里就会报错 如果上述没问题还会做循环依赖的判断,主要逻辑在breakCycl ...

  10. 【iCore3 双核心板_FPGA】例程十二:Modelsim仿真实验

    实验指导书及代码包下载: http://pan.baidu.com/s/1bnQEldl iCore3 购买链接: https://item.taobao.com/item.htm?id=524229 ...