Java线程池简析

线程池简介

我们在实现并发功能时会频繁的创建和销毁线程,这样会加大系统的开销,而线程池会缓存一定数量的线程,可以避免这样的情况,并且线程池可以对现场进行简单的管理,简化了并发编程。

ThreadPoolExecutor

Java中的线程池定义为Executor接口,实现这个接口的类为ThreadPoolExecutor,是线程池的真正实现。常用的构造方法为

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory)
  • corePoolSize:线程池中的核心线程数量,核心线程理论上会一直存活,就算是闲置状态。
  • maximumPoolSize:允许线程池最大容纳的线程数,一旦满了,后面新到来的任务会被阻塞。
  • keepAliveTime:线程闲置的超时时长,闲置时间超过就会被销毁,适用于非核心线程。如果ThredPoolExecutor的allowCoreThreadTimeOut设置为true,那么核心线程也会超时销毁。
  • unit:超时时长的单位,为枚举类型,常用的有毫秒 TimeUnit.MILLISECONDS、秒TimeUnit.SECONDS、分TimeUnit.MINUTES。
  • workQueue:任务队列。
  • threadFactory:提供创建线程的功能。

当任务到来的时候,如果核心线程数量没有达到最大核心线程数量,那么就创建核心线程执行任务。如果超过就将任务插入队列等待核心线程空下来。如果队列也满了,那就只有创建非核心线程(或者复用闲置非核心线程)执行任务。如果全部线程数达到最大值,拒绝执行任务。

四种线程池

FixedThreadPool

构造函数如下

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
  • 核心线程和线程数一样说明只有核心线程,那么线程都不会被回收,可以很快的响应任务。
  • 且队列没有没有大小限制,可以看出新到来的任务肯定不会被拒绝,因为队列不会满,所有任务都可以被执行(核心线程满了就等待)。

CachedThreadPool

构造函数如下

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
  • 没有核心线程,且线程数是int的最大值,适用于大量的任务。
  • SynchronousQueue实际上是不能插入的,所以任务到来的时候,首先没有核心线程,那么就会插入队列等待核心线程,但是这个队列不能插入,所以开启非核心线程执行,也就是说任务到来立马执行,适用于大量且耗时少的任务。

ScheduledThreadPool

构造函数如下

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

    public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory);
    }

SingleThreadExecutor

构造函数如下

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

就一个核心线程,线程只允许一个,等待队列没限制,也就是说任务是串行执行的,不用考虑同步的问题。

执行任务

执行Runnable

public class Main {

    public static void main(String[] args) {
        ExecutorService exe = Executors.newCachedThreadPool();
        for (int i = 0; i != 5; i++) {
            exe.execute(new Task());
        }
        exe.shutdown();
    }

}

class Task implements Runnable {

    @Override
    public void run() {
        // do something here
    }
}

通过execute执行任务,shutdown()方法可以防止新任务被提交给这个Executor,执行完之前的所有任务后会尽快退出。

执行Callable

Runnable执行任务不返回任何值,想要有返回值的话可以使用Callable

public class Main {

    public static void main(String[] args) {
        ExecutorService exe = Executors.newCachedThreadPool();
        List<Future<String>> results = new ArrayList<>();
        for (int i = 0; i != 5; i++) {
            results.add(exe.submit(new Task()));
        }
        exe.shutdown();
        for (Future<String> fs : results) {
            try {
                System.out.println(fs.get());
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

class Task implements Callable<String> {

    public static int i = 0;

    @Override
    public String call() {
        return i++ + "";
    }
}

首先确定返回值的类型,这里是String,执行的方法是call而不是run。使用submit提交任务而不是execute,submit会返回Future的值,然后我们遍历通过get()方法拿到返回值。值得注意的是,当Future未完成的时候,get()方法会阻塞,直到完成拿到返回值,我们可以通过isDone()判断是否完成。

阅读更多
版权声明:本文为博主原创文章,转载请声明原文地址。 https://blog.csdn.net/a62321780/article/details/52373056
个人分类: Java
上一篇Android事件分发机制详解
下一篇打开EventBus3.0的正确姿势
想对作者说点什么? 我来说一句

java 线程池

2011年10月12日 198KB 下载

JAVA几个常见错误简析

2007年06月04日 45KB 下载

Java线程池使用说明

2018年02月24日 576KB 下载

STL简析入门基础学习

2011年05月16日 61KB 下载

简析搜索引擎实现原理

2010年12月13日 535KB 下载

java 手术任务(线程池

2010年06月21日 60KB 下载

Java线程池的原理与实现

2010年05月14日 14KB 下载

java线程池完整代码

2009年03月20日 40KB 下载

java线程池实例

2012年04月17日 5.77MB 下载

java线程池

2015年12月02日 44KB 下载

没有更多推荐了,返回首页

关闭
关闭