现在做的这个华为云TaurusDB比赛中,参考的之前参加过阿里的PolarDB大赛的两个大佬的代码,发现都有用到CountDownLatch这个类,之前看代码的时候也看过,但是没有搞得很明白,自己写也写不出来,在此自己先学习一下。
字面理解:CountDownLatch:数量减少的门栓。
创建这样一个门栓
CountDownLatch countDownLatch = new CountDownLatch(count);
参数:count,门栓的计数次数。
在所有线程执行完成之前,调用countDownLatch.await()阻塞主线程。
每当一个线程执行完一个指定动作之后,count就会减少1,当count等于0时,主线程不再阻塞,开始继续执行下面的代码,当count大于0时,主线程一直阻塞,等待count变为0。每个线程动作执行结束后,执行countDownLatch.countDown(),这个门栓的count减一。
int ThreadNum = 16; CountDownLatch countDownLatch = new CountDownLatch(ThreadNum); for(int i = 0; i < ThreadNum ; i++){ final int finalI = i; new Thread(() -> { int n = 0; System.out.println("线程应该做的事情"); while(n < 10){ n++; } countDownLatch.countDown(); }).start(); } try{ countDownLatch.await(); }catch(InterruptedException e){ logger.infor("InterruptedException!!"); }
其实线程池之前的ipv6的项目里用过,但是也忘记得差不多了,复习一下。
线程在创建和关闭时都需要花费时间,如果为每一个小的任务都创建一个线程,可能创建和销毁线程所用的时间会多于该线程真实工作所消耗的时间,就会得不偿失。除了时间,空间也需要考虑,线程本身也是要占用内存空间的,大量的线程会食用过多的内存资源,可能会造成OOM。另外在回收时,大量的线程会延长GC的停顿时间。
因此在生产环境中使用线程必须对其加以控制和管理
使用线程池之后,创建线程变成了从线程池中获得空闲的线程,关闭线程变成了归还线程给线程池。
通过ThreadPoolExecutor可以创建一个线程池,ThreadPoolExecutor实现了Executors接口。
举个栗子:
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class ThreadPoolTest { public static void main(String[] args) { ThreadPoolExecutor pool = new ThreadPoolExecutor(10,20,60, TimeUnit.SECOUNDS,new ArrayBlockingQueue<Runnable>(15000),new ThreadFactory(){ private AtomicInteger threadId = new AtomicInteger(0); @Override public Thread newThread(Runnable r){ Thread thread = new Thread(r); thread.setDaemon(true); String prefix = "thread-"; thread.setName(prefix+threadId.incrementAndGet()); return thread; } }); } }
这样就创建了一个线程池。参数依次解释:
corePoolSize:指定了线程池中线程的数量,线程池中可以有10个存活的线程
maximumPoolSize:指定了线程池中最大的线程数,线程池中最多能有20个存活的线程
keepAliveTime:当线程池中的数量超过corePoolSize时,这些线程在多长时间会被销毁,60s
unit:keepAliveTime的单位
workQueue:任务队列,被提交但是没有被执行的任务存在的地方。他是一个BlockingQueue<Runnable>接口的对象。
threadFactory:线程工厂,你想创建什么样子的线程
重点说一下workQueue:
根据队列的功能分类,可以使用以下几种BlockingQueue接口
补充:Java中CountDownLatch,CyclicBarrier以及Semaphore的使用场景
Java并发包中提供了很多有用的工具类来帮助开发者进行并发编程,今天我就来说说CountDownLatch,CyclicBarrier以及Semaphore这三个的用法和使用场景。
CountDownLatch一般是用于某个线程等待其他线程执行完之后,它才能执行。例如一家人在等待爸爸妈妈回家,才能进行晚宴,示例代码如下:
public class CountDownLatchTest { public static void main(String[] args) throws Exception { final CountDownLatch cdl = new CountDownLatch(2); new Thread(){ public void run() { try { System.out.println("等待老爸回家..."); Thread.sleep(5000); cdl.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } }; }.start(); new Thread(){ public void run() { try { System.out.println("等待老妈回家..."); Thread.sleep(5000); cdl.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } }; }.start(); cdl.await(); System.out.println("老爸老妈回来了..."); System.out.println("晚宴开始了..."); } }
CyclicBarrier一般是一组线程等待至某个状态,然后这一组线程才能同时执行(感觉跟CountDownLatch有点类似啊,不过仔细想想还是有差别的,感觉容易混淆)。
代码示例如下:
public class CyclicBarrierTest { public static void main(String[] args) { int count = 3; CyclicBarrier cb = new CyclicBarrier(count, new Runnable() { @Override public void run() { //此处所有线程都调用了await方法之后,会走到这里 System.out.println("所有线程操作完成之后都调用了await方法"); } }); for(int i=0;i<count;i++){ new WriteLogHandler(cb).start(); } } static class WriteLogHandler extends Thread{ private CyclicBarrier cb = null; public WriteLogHandler(CyclicBarrier cb) { this.cb = cb; } @Override public void run() { try { System.out.println("线程:" + Thread.currentThread().getName() + "开始写日志"); Thread.sleep(2000); System.out.println("线程:" + Thread.currentThread().getName() + "写日志结束,等待其他线程"); cb.await(); System.out.println("所有线程写日志数据结束,继续其他操作"); } catch (Exception e) { e.printStackTrace(); } } } }
Semaphore类似锁的用法,用于控制对某资源的访问权限,示例代码如下: public class SemaphoreTest { public static void main(String[] args) { ExecutorService executor = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(5); for(int i=0;i<10;i++){ final int num = i; executor.execute(new Runnable() { @Override public void run() { try { semaphore.acquire(); System.out.println("正在执行任务" + num); Thread.sleep((long)Math.random() * 1000); System.out.println("任务" + num + "执行结束"); semaphore.release(); } catch (Exception e) { e.printStackTrace(); } } }); } executor.shutdown(); } }
以上就是这三个并发工具类的使用场景和示例,仅为个人经验,希望能给大家一个参考,也希望大家多多支持小牛知识库。如有错误或未考虑完全的地方,望不吝赐教。欢迎大家一起交流。
本文向大家介绍详解Java线程同步器CountDownLatch,包括了详解Java线程同步器CountDownLatch的使用技巧和注意事项,需要的朋友参考一下 Java程序有的时候在主线程中会创建多个线程去执行任务,然后在主线程执行完毕之前,把所有线程的任务进行汇总,以前可以用线程的join方法,但是这个方法不够灵活,我们可以使用CountDownLatch类,实现更优雅,而且使用线程池的
本文向大家介绍java多线程CountDownLatch与线程池ThreadPoolExecutor/ExecutorService案例,包括了java多线程CountDownLatch与线程池ThreadPoolExecutor/ExecutorService案例的使用技巧和注意事项,需要的朋友参考一下 1、CountDownLatch: 一个同步工具类,它允许一个或多个线程一直等待,直到其他线
本文向大家介绍Java 线程池详解,包括了Java 线程池详解的使用技巧和注意事项,需要的朋友参考一下 系统启动一个线程的成本是比较高的,因为它涉及到与操作系统的交互,使用线程池的好处是提高性能,当系统中包含大量并发的线程时,会导致系统性能剧烈下降,甚至导致JVM崩溃,而线程池的最大线程数参数可以控制系统中并发线程数不超过次数。 一、Executors 工厂类用来产生线程池,该工厂类包含以下几个静
本文向大家介绍详解Java多线程编程中CountDownLatch阻塞线程的方法,包括了详解Java多线程编程中CountDownLatch阻塞线程的方法的使用技巧和注意事项,需要的朋友参考一下 直译过来就是倒计数(CountDown)门闩(Latch)。倒计数不用说,门闩的意思顾名思义就是阻止前进。在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程。
问题内容: 我们在Java中使用了三种不同的多线程技术 -Fork / Join pool,Executor Service和CountDownLatch 叉子/加入池 (http://www.javacodegeeks.com/2011/02/java-forkjoin-parallel- programming.html ) Fork / Join框架旨在使分治算法易于并行化。这种类型的算法非
问题内容: 有人可以帮助我了解什么是Java 以及何时使用它吗? 对于该程序的工作方式,我没有一个很清楚的想法。据我了解,所有三个线程同时启动,每个线程将在3000ms之后调用CountDownLatch。因此,递减计数将逐一递减。锁存器变为零后,程序将打印“ Completed”。也许我的理解方式不正确。 // ------------------------------------------