Multi-threaded programming of advanced --JUC Executors frame design idea to check it out

1, the starting point of learning

Executors framework of the whole package JUC classes / interfaces relations in the framework of the most complex, to really understand the premise of Executors framework is clear rationale relationship between the various modules, a strategically advantageous position, from whole to part to a thorough understanding of the function of each module and design behind ideas!

This article from the Executor, ExecutorService, ScheduledExecutorService, ThreadFactory and Callable these core modules to analyze.

2, from the Executor talk

JDK 1.5 is Executor when introduced as an interface JUC, the main purpose of decoupling is introduced into the interface and task execution task itself. When we perform a task by a thread before, often need to create a thread .satrt () to perform the task,

The Executor interface decoupling the mission and tasks, the interface is only one way to the Senate for the task to be performed.

public interface Executor {
    /** * 执行给定的Runable任务 * 根据Executor接口的实现类不同,具体执行方式也不同 */ void execute(Runnable command); }

We can perform a task like this, without having to create a thread heart

Executor executor = anExecutor
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());

As the Executor is just an interface, all in accordance with its implementation of different, specific tasks to perform different, see the source code comments, we can know such as:

2.1, sync tasks

class DirectExecutor implements Executor { public void execute(Runnable r) { r.run(); } }}

2.2, asynchronous tasks

 class DirectExecutor implements Executor { public void execute(Runnable r) { r.run(); } }}

2.3, queuing for the task execution

 class SerialExecutor implements Executor { final Queue<Runnable> tasks = new ArrayDeque<Runnable>(); final Executor executor; Runnable active; SerialExecutor(Executor executor) { this.executor = executor; } public synchronized void execute(final Runnable r) { tasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (active == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((active = tasks.poll()) != null) { executor.execute(active); } } }}

These examples given above source, just to give some possible Executor implementations, JUC package provides a concrete implementation class Executor of many, the key here is to understand the design of Executor - the implementation of the decoupling of tasks and missions.

3, enhanced ExecutorService

Because the function Executor interface is very simple, for it enhanced, JUC also provides a program called ExecutorService interface that enhances it reaches what things?

You can see, ExecutorService increased control over the task on the basis of the Executor, but also includes management of their life cycle, there are four categories:

1, close the actuator to prohibit job submission

2, monitors the execution status

3, to provide support for asynchronous tasks

4, provides support for processing tasks

4, periodic task scheduling --ScheduledExecutorService

在开发环境中,我们可能需要提交给执行器某些任务能够定时执行或者周期性执行,我们可以自己去实现Executor 接口来创建符合我们需要的类,Doug Lea 已经考虑好了这类需求,所有在ExecutorService 的基础之上,又提供了一个接口 ScheduledExecutorService。

案例演示

public class ScheduleExecutorTest {
    public static void main(String[] args) { ScheduledExecutorService scheduler=Executors.newScheduledThreadPool(4); //开始执行时间1秒后,每隔1秒执行一次任务 final ScheduledFuture<?>scheduledFuture=scheduler.scheduleAtFixedRate(new BeepTask(),1,1,TimeUnit.SECONDS); //5秒后,取消任务,关闭线程池 scheduler.schedule(()->{ scheduledFuture.cancel(true); System.out.println("over"); scheduler.shutdownNow(); },5,TimeUnit.SECONDS); } private static class BeepTask implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"beep!"); } } }

注意:scheduleAtFixedRate 方法返回一个ScheduledFuture 对象,ScheduledFuture其实就是在Future 的基础上增加了延迟功能。通过ScheduledFuture 可以取消一个任务的执行。

ScheduledExecutorService 完整接口说明如下:

public interface ScheduledExecutorService extends ExecutorService { /** * 提交一个待执行的任务, 并在给定的延迟后执行该任务. * * @param command 待执行的任务 * @param delay 延迟时间 * @param unit 延迟时间的单位 */ public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit); /** * 提交一个待执行的任务(具有返回值), 并在给定的延迟后执行该任务 * * @param callable 待执行的任务 * @param delay 延迟时间 * @param unit 延迟时间的单位 * @param <V> 返回值类型 */ public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit); /** * 提交一个待执行的任务 * 该任务在 initialDelay 后开始执行, 然后在initialDelay+period 后执行, 接 * 着在 initialDelay + 2 * period 后执行, 依此类推 * * @param command 待执行的任务 * @param initialDelay 首次执行的延迟时间 * @param period 连续执行之间的周期 * @param unit 延迟时间的单位 */ public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit); /** * 提交一个待执行的任务 * 该任务在 initialDelay 后开始执行, 随后在每一次执行终止和下一次执行开始之间 * 都存在给定的延迟 * 如果任务的任一执行遇到异常, 就会取消后续执行. 否则, 只能通过执行程序的取消或 * 终止方法来终止该任务 * * @param command 待执行的任务 * @param initialDelay 首次执行的延迟时间 * @param delay 一次执行终止和下一次执行开始之间的延迟 * @param unit 延迟时间的单位 */ public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit); } 

至此,Executors 框架中的三个最核心的接口介绍完毕,三个核心接口关系如下

5、生产Executor的工厂

通过前面的介绍,读者应该对Executors框架有了一个初步的认识,Executors 框架就是用来解耦任务本身与任务的执行,并提供了三个核心(Executor、ExecutorService、ScheduledExecutorService)接口来满足使用者的需求!

1、Executor:提交普通的可执行任务

2、ExecutorService:提供对线程池生命周期的管理、异步任务的支持

3、ScheduledExecutorService:提供对任务周期性执行的支持

既然有了接口,那么就有相应的实现类,JUC 提供了许多默认的接口实现,用户如果自己去创建这些类的实例,就需要了解这些类的细节,我们可不可以仅仅根据一些参数就能创建这些实例呢?

因此Executors类就是专门用于创建上述接口的实现类对象,Executors其实就是一个简单工厂,它的所有方法都是static的,Executors 一共提供了五类可供创建的Executors执行器实例。

1、固定线程数的线程池

    /**
     * 创建一个具有固定线程数的Executor
     *
     * @param nThreads 核心线程数(银行有五个窗口,平时开三个窗口(核心线程数))
     */
    public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } /** * 创建一个具有固定线程数的Executor. * 在需要时使用提供的 ThreadFactory 创建新线程. * * @param nThreads 核心线程数 * @param threadFactory 创建线程的工厂 */ public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); } public interface ThreadFactory { //创建了一个线程 Thread newThread(Runnable r); } 

ThreadFactory 作为一个线程工厂,我们可以由外部指定ThreadFactory实例,以决定线程具体的创建方式。

下面就以 DefaultThreadFactory为例

//默认的线程工厂
static class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1);//原子性 private final ThreadGroup group;//线程组 private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } }

可以看到,DefaultThreadFactory 初始化的时候定义了线程组、线程名称等信息,每创建一个线程,都给线程统一分配了这些信息,避免了手动new的方式创建线程,又可以进行工厂复用。

2、单个线程的线程池

 /**
     * 创建一个使用单个 worker 线程的 Executor
     */
    public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } /** * 创建一个使用单个 worker 线程的 Executor * 在需要时使用提供的 ThreadFactory 创建新线程 * * @param threadFactory 线程工厂 */ public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory)); } //对返回的Executor实例进行一个包装 static class FinalizableDelegatedExecutorService extends DelegatedExecutorService { FinalizableDelegatedExecutorService(ExecutorService executor) { super(executor); } protected void finalize() { super.shutdown(); } } 

我们可以看到,只有单个线程上文线程池其实就是指定好了线程数为1的固定线程池,主要区别就是返回的Executor实例用了一个 FinalizableDelegatedExecutorService对象 进行包装,它核心继承了 DelegatedExecutorService ,这是个包装类,实现了 ExecutorService的所有方法,但是内部实现其实都委托给了传入的 ExecutorService 实例。

为什么要多此一举呢?

因为返回的 ThreadPoolExecutor 包含一些设置线程池大小的方法,对于只有单个线程的线程池来说,我们是不希望用户通过强转的方式使用这些方法的,所以需要这么一个包装类,只暴露ExecutorService 本身的方法。

3、可缓存的线程池

/**
 * 创建一个可缓存线程的Execotor
 * 如果线程池中没有线程可用, 则创建一个新线程并添加到池中
 * 如果有线程长时间未被使用(默认60s,可通过threadFactory配置), 则从缓存中移除
 */
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } /** * 创建一个可缓存线程的Execotor. * 如果线程池中没有线程可用, 则创建一个新线程并添加到池中; * 如果有线程长时间未被使用(默认60s, 可通过threadFactory配置), 则从缓存中移除. * 在需要时使用提供的 ThreadFactory 创建新线程. */ public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }

可以看到,返回的还是ThreadPoolExecutor对象,只是指定了超时时间,另外线程池中线程的数量在[0, Integer.MAX_VALUE]之间。

4、可延时/周期性调度的线程池

/**
 * 创建一个具有固定线程数的 可调度Executor.
 * 它可安排任务在指定延迟后或周期性地执行.
 */
public static ScheduledExecutorService newSingleThreadScheduledExecutor() { return new DelegatedScheduledExecutorService (new ScheduledThreadPoolExecutor(1)); } /** * 创建一个具有固定线程数的 可调度Executor. * 它可安排任务在指定延迟后或周期性地执行. * 在需要时使用提供的 ThreadFactory 创建新线程. */ public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) { return new DelegatedScheduledExecutorService (new ScheduledThreadPoolExecutor(1, threadFactory)); }

5、Fork/Join线程池

/**
 * 创建具有指定并行级别的ForkJoin线程池.
 */
public static ExecutorService newWorkStealingPool(int parallelism) { return new ForkJoinPool (parallelism, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); } /** * 创建并行级别等于CPU核心数的ForkJoin线程池. */ public static ExecutorService newWorkStealingPool() { return new ForkJoinPool (Runtime.getRuntime().availableProcessors(), ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); }

3、总结

至此,Executors框架就基本介绍完了,我们看下他的类图

 来源:站长导航

Guess you like

Origin www.cnblogs.com/1994july/p/12390552.html