JAVA创建线程池

阅读了阿里JAVA开发手册泰山版,其中关于线程池的创建有个强制要求:线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这 样的处理方式更加明确线程池的运行规则,规避资源耗尽的风险。

说明:Executors返回的线程池对象的弊端如下:

    1)FixedThreadPool和SingtelThreadPool

         允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。

     2)CachedThreadPool

         允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。 

下面看看使用Executors创建线程的方式

1.创建CachedThreadPool

  1.1 使用Executors创建

ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();

 Executors的newCachedThreadPool()方法

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

newCachedThreadPool()方法的第二个参数是线程池允许的最大线程数,使用该方法创建的线程池默认使用Integer.MAX_VALUE作为线程池允许的最大线程数。所以使用该线程池时可能会创建大量的线程,从而导致内存溢出。

 1.2 使用ThreadPoolExecutor,自定义参数创建

ThreadPoolExecutor cacheThreadPool = new ThreadPoolExecutor(10, 100, 60L,             
                                                            TimeUnit.SECONDS, 
                                                     new SynchronousQueue<Runnable>(true));

构建SynchronousQueue的参数fair表示创建的同步队列是公平的还是不公平的,true则使用FIFO规则的队列(Queue),false则使用栈(Stack)

public SynchronousQueue(boolean fair) {
	  transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}

2. 创建FixedThreadPool

  2.1 使用Executors创建

ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(10);

  Executors的newFixedThreadPool()方法

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

public LinkedBlockingQueue(int capacity) {
    if (capacity <= 0) throw new IllegalArgumentException();
    this.capacity = capacity;
    last = head = new Node<E>(null);
}

LinkedBlockingQueue默认创建的队列没有指定任务队列的容量,使用默认容量Integer.MAX_VALUE,因此可能会堆积大量的任务,导致内存溢出。

同理SingleThreadExecutor。

 

3. ThreadPoolExecutor submit()和execute()执行任务的区别

  1. submit()方法是ThreadPoolExecutor父类AbstractExecutorService中实现的, 最后都会调用到AbstractExecutorService的实现类中的execute()方法。
  2. execute()方法是ThreadPoolExecutor实现的。
  3. submit()有返回值 Future,所以submit()方法执行任务是异步的。
  4. execute()没有返回值,不是异步的。

AbstractExecutorService中的submit()方法

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask); // execute()在子类中实现
    return ftask;
}

 ThreadPoolExecutor中实现的execute()方法

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

仅供参考

关于阿里JAVA开发手册泰山版,详情点击这里免费下载。

说明:下载的手册不得用作任何商业意图,否则将依法追究相关法律责任,谨记。

如有侵权,请联系博主。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章