Java线程池简析

原创 2016年08月30日 21:16:03

线程池简介

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

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

版权声明:本文为博主原创文章,转载请声明原文地址。

相关文章推荐

简析JAVA的XML编程

  • 2009年07月31日 15:54
  • 50KB
  • 下载

JAVA几个常见错误简析

  • 2008年09月19日 23:39
  • 29KB
  • 下载

java线程简析

线程简析: 线程是正在运行程序进程中单一的执行流,一个进程对应一个程序,一个程序可以有多个进程,进程有自己的独立空间,线程只能共享进程中的空间,一个进程至少包含一个线程。线程最大的特点是可以同时并发...

java web 简析-- TCP协议概要

  • 2015年10月20日 09:51
  • 2.39MB
  • 下载

C++与Java混合编程简析

  • 2012年03月05日 13:44
  • 515KB
  • 下载

Java多线程简析——Synchronized(同步锁)、Lock以及线程池

Java多线程 Java中,可运行的程序都是有一个或多个进程组成。进程则是由多个线程组成的。 最简单的一个进程,会包括mian线程以及GC线程。 线程的状态 线程状态由以下一张网上图片来说明: 在...

JAVA几个常见错误简析

  • 2007年06月04日 09:23
  • 45KB
  • 下载

JDK框架简析--java.util包中的工具类库

在本节中,简析java.util包所包含的工具类库,主要是集合相关的类库,其次还有正则、压缩解压、并发、日期时间等工具类。...

java 多线程 wait() 以及 notirfy() 简析

文章来源:http://www.blogjava.net/hk2000c/archive/2007/12/19/168761.htmlclass ThreadA { public static v...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java线程池简析
举报原因:
原因补充:

(最多只允许输入30个字)