java并发编程实战第六章笔记

第六章 任务执行

1. Executor框架

public interface Executor{
	void execute(Runnable command);
}
该框架能支持多种不同类型的任务执行策略。它提供了一种标准的方法将任务的提交过程与执行过程解耦,并用Runnable来表示任务。Executor的实现还提供了对生命周期的支持,以及统计信息收集,应用程序管理机制和性能监视等机制。
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * 基于线程池的Web服务器
 * @author cream
 *
 */
public class TaskExecutionWebServer {
	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() {
				public void run() {
					//处理请求
				}
			};
			exec.execute(task);
		}
	}
}

上述代码,通过使用Executor,将请求处理任务的提交与任务的实际执行解耦。

2. 线程池

线程池的优势: 
1. 通过重用现有的线程而不是创建新线程,可以减少创建和销毁线程的开销 
2. 当请求到来时,由于线程已经存在,可以减少等待时间,从而提高了响应性

可以通过调用Executors中的静态工厂方法之一来创建一个线程池:

newFixedThreadPool:创建一个定长的线程池, 每当提交一个任务就创建一个线程, 直到达到池的最大长度, 这时线程池会保持长度不再变化. (一任务一线程) 

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

newSingleThreadExecutor :创建一个单线程化的executor, 它只创建唯一的工作者线程来执行任务, 如果这个线程异常结束, 会有另一个取代它, 但是任务会保存在一个queue中等待执行. (多任务一线程) 

newScheduleThreadPool :创建一个定长的线程池, 而且支持定时的以及周期性执行任务, 类似timer.(定时线程池) 

3.Executor的生命周期

为了解决执行服务的生命周期问题,Executor扩展了ExecutorService接口,添加了生命周期的管理方法

public interface ExecutorService extends Executor {
     void shutdown();
     List<Runnable> shutdownNow();
     boolean isShutdown();
     boolean isTerminated();
     boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
     ....
}

生命周期状态有三种:运行,关闭和已终止。

shuting down(关闭)状态: 
shutdown:将停止接受新的任务, 同时等待已经提交的任务完成, 包括尚未完成的任务 
showdownNow:会启动一个强制的关闭过程, 尝试取消所有运行中的任务和排在队列中尚未开始的任务,并把排队中尚未开始的任务返回。

对于关闭后提交到ExecutorService中的任务, 会被(拒接执行处理器)rejected execution handler处理,它会抛弃任务,或者使得execute方法抛出一个未检查的RejectedExecutionException。

terminated(已终止)状态: 

等所有任务都完成之后,进入terminated状态, 可以调用awaitTermination等待ExecutorService到达终止状态, 也可以轮询检查isTerminated判断是否终止. 通常shutdown会紧随awaitTermination之后, 这样可以产生同步地关闭ExecutorService的效果.

4.携带结果的Future和Callable

Exceutor框架使用Runnable作为最基本的任务形式,但是Runnable有一种很大的局限性,它不能返回一个值或抛出一个受检查的异常。

Callable是一种更好的任务形式,它能返回(call)一个值或者抛出一个异常。

Future表示一个任务的生命周期,并提供了相应的方法来判断是否已经完成或取消,以及获取任务的结果和取消任务等。

public interface Callable<V>{
	V call() throws Exception;
}

public interface Future<V>{
	boolean cancel(boolean mayInterruptIfRunning);
	boolean isCancelled();
	boolean isDone();
	V get() throws InterruptedException, ExecutionException, CancellationException;
	V get(long timeout,TimeUnit unit) throws InterruptedException, ExecutionException, CancellationException,TimeoutException;
}

get()方法的行为将取决于任务的状态,如果任务已经完成,那么get会立即返回结果或者抛出一个Exception,如果任务没有完成,那么get将阻塞并直到任务完成。如果任务抛出了异常,那么get将异常封装成ExecutionException并重新抛出,如果任务被取消,那么get抛出CancellationException。如果get抛出了ExecutionException,那么可以通过getCause获得被封装的初始异常。

ExecutorService中的所有submit方法都将返回一个Future,从而将一个Runnable或者Callable任务传递给ExecutorService的submit方法,返回一个Future用于获得任务的执行结果或者取消任务。

5. CompletionService: Executor与BlockingQueue

CompletionService用来将Executor与BlockingQueue进行结合, 将Callable任务提交给它执行, 然后使用类似队列中的take和poll在结果完整时获得这个结果。

public class Test {
    private final ExecutorService executor = Executors.newCachedThreadPool();

    void renderPage(String source) {
        final List<ImageInfo> imageInfos = scanForImageInfo(source);
        CompletionService<ImageData> service = new ExecutorCompletionService<ImageData>(
                executor);

        for (final ImageInfo imageInfo : imageInfos) {
            service.submit(new Callable<ImageData>() {
                public ImageData call() throws Exception {
                    return imageInfo.downloadImage();
                }
            });
        }

        renderText(source);

        for (int i = 0; i < imageInfos.size(); i++) {
            Future<ImageData> f;
            try {
                f = service.take();
                ImageData imageData = f.get();
                renderImage(imageData);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/llcream/article/details/79861910