java 并发——线程 (4)



newCachedThreadPool
创建一个可缓存的线程池,线程池可以自动的扩展线程池的容量,核心线程数量为0.如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }

SynchronousQueue是个特殊的队列。 SynchronousQueue队列的容量为0。当试图为SynchronousQueue添加Runnable,则执行会失败。只有当一边从SynchronousQueue取数据,一边向SynchronousQueue添加数据才可以成功。SynchronousQueue仅仅起到数据交换的作用,并不保存线程。但newCachedThreadPool()方法没有线程上限。Runable添加到SynchronousQueue会被立刻取出。
根据用户的任务数创建相应的线程来处理,该线程池不会对线程数目加以限制,完全依赖于JVM能创建线程的数量,可能引起内存不足。


newScheduledThreadPool
创建一个指定大小的定时任务调度的线程池。此线程池支持定时以及周期性执行任务的需求。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); }



newSingleThreadScheduledExecutor
创建一个单线程的定时任务调度线程池,此线程池支持定时以及周期性执行任务的需求。

public static ScheduledExecutorService newSingleThreadScheduledExecutor() { return new DelegatedScheduledExecutorService (new ScheduledThreadPoolExecutor(1)); } 四、线程辅助类 闭锁 CountDownLatch CountDownLatch 的概念

想起了多线程下载,将整个文件分成了多段,然后多个线程提供下载,每个线程下载一段。当所有的下载线程都执行完之后,主线程通知用户,文件下载完成了。这里存在一个问题,主线程如何知道所有的下载线程都执行完了?
解决思路有很多种,比如我们可以定义一个计数的变量,初始值为下载线程的数量,每个线程执行完,计数变量值 -1,计数器的值为 0 ,我们就知道所有的下载线程都执行完了。这里,我们可能需要对计数器进行相应的同步操作,确保任何时候读取它的状态都是正确的。
幸运的是,java 提供了一个类似计算器的工具类,可以达到此目的。——CountDownLatch 类。
CountDownLatch 位于 java.util.concurrent 包下。是一个同步工具类,用来协调多个线程之间的同步,
CountDownLatch 能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成了任务,然后在CountDownLatch上等待的线程就可以恢复执行任务。

CountDownLatch 的用法

CountDownLatch类只提供了一个构造器:

public CountDownLatch(int count) //参数count为计数值

CountDownLatch 类中有 3 个重要方法:

public void await() throws InterruptedException //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行

public boolean await(long timeout, TimeUnit unit) throws InterruptedException //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行

public void countDown() //将count值减1

CountDownLatch 用法举例:

public class Test { public static void main(String[] args) { final CountDownLatch latch = new CountDownLatch(2); new Thread(){ public void run() { try { System.out.println("子线程"+Thread.currentThread().getName()+"正在执行"); Thread.sleep(2000); System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕"); latch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } }; }.start(); new Thread(){ public void run() { try { System.out.println("子线程"+Thread.currentThread().getName()+"正在执行"); Thread.sleep(3000); System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕"); latch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } }; }.start(); try { System.out.println("等待2个子线程执行完毕..."); latch.await(); System.out.println("2个子线程已经执行完毕"); System.out.println("继续执行主线程"); } catch (InterruptedException e) { e.printStackTrace(); } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjpws.html