关闭

Java线程池简析

标签: java线程池线程并发
128人阅读 评论(0) 收藏 举报
分类:

线程池简介

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

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()判断是否完成。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:17800次
    • 积分:520
    • 等级:
    • 排名:千里之外
    • 原创:37篇
    • 转载:0篇
    • 译文:0篇
    • 评论:18条
    最新评论