c3 Threads - Thread Pools and Executors

是不是线程越多越好呢?

在有I/O瓶颈的程序里,比如大部分网络程序,使用多线程可以提高性能,在一个程序block时,其他程序继续执行,以使cpu别闲着。但是,是不是线程越多越好呢?不是!因为使用多线程本身也是有成本的:创建、销毁线程需要VM销毁资源,需要垃圾回收器忙活,当一个小服务器不停的创建销毁了成百上千个线程时,这本身就是巨大的资源消耗;其次,更重要的是,线程间的切换!如果是cpu-bound的程序,那少切换会使程序更快的执行完!再者,最重要的是,虽然线程可以提高cpu使用率,但是cpu资源也是有限的,如果一味的spawn多的线程,那MIPS和Memory资源就全部花在线程管理上了。


java.util.concurrent中的类Executor可以很容易的管理thread,只需要把Runnable对象丢给pool,然后会得到一个Future对象,可用来查看task执行情况。

看个例子,现在要用java.util.zip.GZIPOutputStream压缩给定目录下的文件。

一方面,需要频繁的I/O操作,read和write。另一方面,压缩时又是cpu-intensive,所以不能创建太多的线程,这里用线程池非常合适。

class GZipRunnable implements Runnable {
	  private final File input;
	  public GZipRunnable(File input) {
	    this.input = input;
	  }
	  @Override
	  public void run() {
	    // don't compress an already compressed file
	    if (!input.getName().endsWith(".gz")) {
	      File output = new File(input.getParent(), input.getName() + ".gz");
	      if (!output.exists()) { // Don't overwrite an existing file
	        try ( // with resources; requires Java 7
	          InputStream in = new BufferedInputStream(new FileInputStream(input));
	                OutputStream out = new BufferedOutputStream(
	                        new GZIPOutputStream(
	                          new FileOutputStream(output)));
	                       ) {
	                          int b;
	                          while ((b = in.read()) != -1) out.write(b);
	                          out.flush();
	                      } catch (IOException ex) {
	                        System.err.println(ex);
	                      }
	                    }
	                 }
	             }
	   }

注意jdk7的try-with-resource statement,inputstream和outputstream在try的开头声明,在try的结尾处自动close。

还有,将input和output都buffering!尤其对I/O-limited的网络程序,使用buffer的最坏结果是没有效果,最好结果是在性能上提高一个数量级。

 class GZipAllFiles {
	  public final static int THREAD_COUNT = 4;
	  public static void main(String[] args) {
	    ExecutorService pool = Executors.newFixedThreadPool(THREAD_COUNT);
	    for (String filename : args) {
	      File f = new File(filename);
	      if (f.exists()) {
	        if (f.isDirectory()) {
	          File[] files = f.listFiles();
	          for (int i = 0; i < files.length; i++) {
	            if (!files[i].isDirectory()) { // don't recurse directories
	              Runnable task = new GZipRunnable(files[i]);
	              pool.submit(task);
	            }
	          }
	        } else {
	          Runnable task = new GZipRunnable(f);
	          pool.submit(task);
	        }
	      }
	    }
	    pool.shutdown();
	  }
	}

注意到pool.shutdown(),在你将所有task都添加到pool后就可以调用该方法,调用后并不会丢弃没有执行的task,只是告诉pool,没有新任务加入了,在执行完已有task后就可以shutdown了。
















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值