그것을 확인하기 위해 고급 --JUC 집행 인 프레임 디자인 아이디어의 프로그래밍 멀티 스레드

학습의 1, 시작 지점

각 모듈과 디자인 뒤의 기능에 대한 철저한 이해에 대한 부분 전체에서 다양한 모듈, 전략적으로 유리한 위치 사이의 명확한 근거 관계는 가장 복잡한의 틀에서 전체 패키지의 집행 프레임 워크는 JUC 클래스 / 인터페이스 관계, 정말 집행 프레임 워크의 전제를 이해하는 것입니다 아이디어!

집행자 된 Executor, ExecutorService, ScheduledExecutorService, ThreadFactory 및 호출 가능 이러한 핵심 모듈에서이 문서 분석합니다.

2 집행자의 이야기에서

JUC는, 디커플링의 주요 목적은 인터페이스 및 작업 실행 작업 자체에 도입되는 인터페이스로 소개 할 때 JDK 1.5 집행자이다. 우리가 전에 스레드로 작업을 수행 할 때, 종종 작업을 수행 할 스레드 .satrt ()를 작성해야합니다,

임무 및 작업 디커플링 인터페이스 집행자는, 인터페이스는 작업을 수행하는 데 필요한 상원에 단 하나의 방법입니다.

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

우리는 스레드의 마음을 만들 필요없이,이 같은 작업을 수행 할 수 있습니다

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

집행자는 단지 인터페이스, 다른, 특정 작업의 구현에 따라 모두 다른 수행이기 때문에, 우리는 등을 알 수 있으며, 소스 코드의 주석을 참조하십시오

2.1 동기화 태스크

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

2.2 비동기 작업

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

작업 실행을 위해 대기 2.3,

 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); } } }}

작업 및 임무의 디커플링의 구현 - 소스 위에 주어진 이러한 예, 그냥 JUC 패키지는 많은 사람들의 구체적인 구현 클래스 실행 프로그램을 제공, 몇 가지 가능한 집행자 구현을 제공하기 위해, 여기에 키 집행자의 디자인을 이해하는 것입니다.

3 ExecutorService를 향상

기능 실행자 인터페이스는 매우 간단하기 때문에 그것을 향상을 위해, JUC도 강화합니다 그것이 어떤 일을 도달 ExecutorService를 인터페이스라는 프로그램을 제공?

당신은 ExecutorService를 실행 프로그램에 기초하여 작업을 제어 할 증가뿐만 아니라, 자신의 라이프 사이클 관리, 네 가지 범주가 포함 볼 수 있습니다 :

1 일 제출 금지 액츄에이터를 닫고

도 2의 실행 상태를 모니터링

3, 비동기 작업에 대한 지원을 제공합니다

4, 프로세싱 태스크를위한 지원을 제공한다

4,주기적인 작업 예약 --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框架就基本介绍完了,我们看下他的类图

 来源:站长导航

추천

출처www.cnblogs.com/1994july/p/12390552.html