江湖开发者 | Java粉
网站地图
首页> Java优化> Executor框架
2016
06-12

Executor框架

Executor框架


java中的线程框架,Executor框架,提供了一个灵活的线程池的实现。


// 模拟单线程服务器
public class SingleThreadWebServer {
	static void handlerRequest(Socket connection){}
	public static void main(String[] args) throws IOException {
		ServerSocket socket = new ServerSocket(80);
		while(true){
			Socket connection = socket.accept();
			handlerRequest(connection);  //模拟处理请求代码
		}
	}
	/***
	 * 对于一个单线程化的服务器,阻塞不仅仅延迟了当前请求的完成,而且还完全阻止了需要被处理
	 * 的等待请求。
	 */
}
// WebServer 为每个请求启动一个新的线程   每任务每线程(thread-per-task)
public class ThreadPerTaskWebServer {
	static void handlerRequest(Socket connection){}
	public static void main(String[] args) throws IOException {
		ServerSocket socket = new ServerSocket(80);
		while(true){
			final Socket connection = socket.accept();
			Runnable task = new Runnable(){
				@Override
				public void run() {
					handlerRequest(connection);  //模拟处理请求代码
				}
			};
			new Thread(task).start();
		}
	}
}
public class TaskExecutionWebServer {
	
	static void handlerRequest(Socket connection){}
	private static final int NTHREADS = 100;
	private static final Executor exec = Executors.newFixedThreadPool(NTHREADS);
	
	public static void main(String[] args) throws IOException {
		ServerSocket socket = new ServerSocket(80);
		while(true){
			final Socket connection = socket.accept();
			Runnable task = new Runnable(){
				@Override
				public void run() {
					handlerRequest(connection);  //模拟处理请求代码
				}
			};
			exec.execute(task);
		}
	}
}

上面三个方法模拟了三种线程执行策略:


每一种:单线程顺序执行时,CPU利用率是非常低的,当并发过多时,无法提供良好的吞吐量或快速的响应性。

第二种:"每任务每线程",活动线程会消耗系统资源,尤其是内存.如果可运行的线程数多于可用的处理器数,线程将会空闲.大量空闲线程占用更多内存,给垃圾回收器带来压力,而且大量线程在竞争CPU资源时,还会产生其他的性能开销。如果你已经有了足够多的线程保持所有CPU忙碌,那么再创建更多的线程是有百害而无一利的。

第三种: 使用了线程池,合理的线程数(线程数可以根据处理器的个数来计算)可以给程序带来更快的响应性和更大的吞吐量,并且不会造成线程资源过度开销。


无论何时当你看到这种形式的代码: new Thread(runnable).start)(); 并且你可能最终希望获得一个更加灵活的执行策略时,请认真考虑使用Executor代替Thread.


Executor框架中的线程池


在线程池中执行,这种方法有很多"每任务每线程"无法比拟的优势。重用存在的线程,而不是创建新的线程,这可以在处理多请求时抵消线程创建,消亡产生的开销。另一项额处的好处就是,在请求到达时,工作者线程通常已经存在,用于创建线程的等待时间并不会延迟任务的执行,因此提高了响应性.通过适当地调整线程池的大小,可以得到足够多的线程以保持处理器忙碌,同时还可以防止过多的线程相互竞争资源,导致应用程序耗尽内存或者失败。


类库中提供了一个灵活的线程池实现和一些有用的预设配置。可以通过调用Executors中的某个静态工厂方法来创建一个线程池:


newFixedThreadPool 创建一个定长的线程池,每当提交一个任务就创建一个线程,直到达到池的最大长度,这时线程池会保持长度不再变化(如果一个线程由于非预期的Exception而结束,线程池会补充一个新的线程)。

newCacheThreadPool创建一个可缓存的线程池,如果当前线程池的长度超过了处理的需要时,它可以灵活地回收空闲的线程,当需求增加时,它可以灵活地添加新的线程,而并不会对池的长度作任何限制.

newSingleThreadExecutor创建一个单线程化的executor,它只创建唯一的工作者线程来执