Java Executor框架

Executor 类结构

在这里插入图片描述
Executor提供了一种提交任务与任务具体如何执行的解耦方式。
ExecutorService 提供了shutdown,shutdownNow,invokeAll,invokeAny等线程管理的方法。

Runnable,Callable

Execucor执行的任务需要实现Runnable 或者 Callable
Runnable是没有返回结果的,线程执行的方法是run方法,run方法不会抛出异常。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Callable可返回结果,线程执行的方法是call方法,call方法可抛出异常

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

当线程池submit Callable的时候,会把Callable封装FutureTask,线程池执行的是FutureTask这个对象,同事返回这个FutureTask,FutureTask也实现了future,future示异步执行结果。我们可以通过get获取任务结果,cancel取消任务执行。

public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

Future

future表示异步执行结果,通过future可以获取任务的结果,可以取消任务的执行。

public interface Future<V> {
	//取消任务的执行
    boolean cancel(boolean mayInterruptIfRunning);
    //是否已经取消
    boolean isCancelled();
    //任务是否已经完成
    boolean isDone();
    //获取任务的执行结果,会等待任务执行完
    V get() throws InterruptedException, ExecutionException;
    //获取任务的执行结果,超时会抛出异常。
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

可以看看Future的实现类FutureTask
futureTask的run方法执行后会调用set(result), set方法会调用的一个方法finishCompletion表示完成了执行,finishCompletion会LockSupport.unpark(t) 解除线程阻塞,让等待获取结果的线程继续执行。get的时候调用awaitDone阻塞当前线程。

 	public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {       
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
    
 	protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            finishCompletion();
        }
    }
    
     private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        LockSupport.unpark(t);
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }
        done();
        callable = null;        // to reduce footprint
    }
    
 public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
        	//如果任务没执行完,会阻塞当前线程等待获取任务执行结果。
            s = awaitDone(false, 0L);
        return report(s);
    }
    

Executors工具类

创建固定数量的线程池,使用了无界队列,这些数量的线程会一直存在直到调用了shutdown()。
使用了无界队列,没有调用shutdown的话不会拒绝任务,任务量很大的时候可能导致内存溢出。

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

创建一条线程的固定线程池,采用无界队列。
使用了无界队列,任务量很大的时候可能导致内存溢出。

 public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

创建缓存的线程池,根据需要创建线程,优先重用以前的线程,60秒内未使用的线程将终止并从缓存中移除。
缓存线程池使用的是传递队列SynchronousQueue,这是一个没有容器的队列,类似于手递手传递而不是先放在一个容器里面,当生产者线程put元素的时候,如果没有消费者take,那么生产者线程就会阻塞。
允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致内存溢出。

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

ThreadPoolExecutor

这是Java里面经常有用到的自定义线程池。我的另外一篇博文里面有详细介绍。
[https://blog.csdn.net/liushengbaoblog/article/details/104899115]

ScheduledThreadPoolExecutor

给初始化延迟后执行任务或者定期执行任务的线程池。
队列使用的是DelayedWorkQueue是一个实现了优先级的延迟队列。DelayedWorkQueue中的任务会进行排序,执行所需时间短的放在前面先被执行。

建议使用ScheduledThreadPoolExecutor 而不是Timer
Timer 中的TimeTask 可能导致线程挂掉,后面的任务将不会执行。ScheduledThreadPoolExecutor 可以捕获异常,并且还能通过重写afterExecute对异常任务做处理。
Timer 是一个线程,如果任务耗时可能会延迟后面的任务。而ScheduledThreadPoolExecutor 可配置多个线程。

  public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值