线程

一:newFixedThreadPool

创建一个线程可重用的并且线程数固定的线程池。

nThreads - 池中的线程数

threadFactory - 创建新线程时使用的工厂

public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newFixedThreadPool(int nThreads,ThreadFactory threadFactory)
二:newCachedThreadPool

创建一个可根据实际情况动态维持线程数的线程池,当任务到来时,如果有已经构造好的空闲线程将重用它们,不创建新的线程。

如果没有可用的空闲线程,则创建一个新线程并添加到池中。并且会终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因

此,长时间保持空闲的线程池不会使用任何资源。

threadFactory - 创建新线程时使用的工厂

public static ExecutorService newCachedThreadPool()
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
三:newSingleThreadExecutor

创建一个使用单个线程的 ExecutorService,以无界队列方式来运行该线程。

threadFactory - 创建新线程时使用的工厂

public static ExecutorService newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)

关于这3类的线程池我引用一下《thinking in java》对它们的描述:

使用FixedThreadPool,你可以一次性的预先执行代价高昂的线程分配,因而也就可以限制线程数的数量,这可以节省时间,因为你不用为每一个任务都固定的付出创建线程的开销。在事件驱动的系统中,需要线程的事件处理器,通过直接从池中获取线程,也可以如你所愿地尽快得到服务。你不会滥用可获得的资源,因为FixedThreadPool使用的Thread对象的数量是有界的。

对于CachedThreadPool,它在程序的执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程,因此它是合理的ExecutorService的首选。只有当这种方式会引发问题时,你才需要切换到FixedThreadPool。

SingleThreadExecutor就是线程数量为1的FixedThreadPool。这对于你希望在另一个线程中连续运行的任何事物(长期存活的任务)来说,都是非常有用的,例如监听进入套接字连接的任务。

=======================================================================

我们再来看一下它们的源码,比如FixedThreadPool:

[java] view plaincopyprint?
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}

所以在本质上,就是创建了一个我们上一篇文章介绍过的ThreadPoolExecutor类。

接下来我们写一个完整的,使用它们的例子:

下面给出了一个网络服务的简单结构,这里线程池中的线程作为传入的请求。它使用了预先配置的 Executors.newFixedThreadPool(int) 方法创建线程池:

[java] view plaincopyprint?
class NetworkService implements Runnable {
private final ServerSocket serverSocket;
private final ExecutorService pool;

public NetworkService(int port, int poolSize)  
    throws IOException {  
  serverSocket = new ServerSocket(port);  
  pool = Executors.newFixedThreadPool(poolSize);  
}  

public void run() { // run the service  
  try {  
    for (;;) {  
      pool.execute(new Handler(serverSocket.accept()));  
    }  
  } catch (IOException ex) {  
    pool.shutdown();  
  }  
}  

}

class Handler implements Runnable {
private final Socket socket;
Handler(Socket socket) { this.socket = socket; }
public void run() {
// read and service request on socket
}
}

这里我们再顺带介绍一下线程池的关闭——shutdown()和shutdownNow()方法。
我们可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池,但是它们的实现原理不同,shutdown的原理是只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。对shutdown()方法的调用可以防止新的任务被提交给这个线程池,当前线程将继续运行在shutdown()被调用之前提交的所有任务

shutdownNow的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。shutdownNow会首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表。

只要调用了这两个关闭方法的其中一个,isShutdown方法就会返回true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于我们应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow。

我们加入shutdown()和shutdownNow()方法来完善一下上面这个例子:

[java] view plaincopyprint?
void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // 防止新的任务被提交上来
try {
// 等待当前已经存在的任务执行完
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow(); // 如果过了指定时间还有任务没有完成,立马停止它们
// 等待任务响应取消命令
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println(“Pool did not terminate”);
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}

至此,对Executors的简单了解结束。下一篇文章我们将对上一篇文章介绍的ThreadPoolExecutor类做一下更深入的研究。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值