当前位置: 首页 > 科技观察

JavaExecutor框架学习总结_0

时间:2023-03-14 21:49:17 科技观察

大多数并发都是通过任务执行来实现的。通常有两种执行任务的方式:串行和并行。classSingleThreadWebServer{publicstaticvoidmain(String[]args)throwsException{ServerSocketsocket=newServerSocket(80);while(true){Socketconn=socket.accept();handleRequest(conn);}}}classThreadPerTaskWebServer{publicstaticvoidmain(String[]argsp{throwsExServerSocketsocket=newServerSocket(80);while(true){finalSocketconn=socket.accept();Runnabletask=newRunnable(){publicvoidrun(){handleRequest(conn);}};newThread(task).start();}}当然,以上两种方式都是有问题的,单线程的问题是并发量会是瓶颈,而多线程的版本就是单独创建线程会导致资源不足,Executor框架任务是一组逻辑工作单元,线程是异步执行任务的机制,JDK提供了Executor接口:publicinterfaceExecutor{voidexecute(Runnablecommand);}Executor接口虽然比较简单,但它是异步任务的基础EXE文件cution框架,可以支持多种不同类型的任务执行策略。它提供了一种将任务提交过程与执行过程分离的标准方法。使用Runnable来表示任务。Executor的实现提供了对生命周期和统计应用管理等机制的支持。Executor基于生产者-消费者模型。提交任务的操作相当于生产者,执行任务的线程相当于消费者。基于Executor的WebServer示例如下:publicclassTaskExecutorWebServer{privatestaticfinalintNTHREADS=100;privatestaticfinalExecutorexec=Executors.newFixedThreadPool(NTHREADS);publicstaticvoidmain(String[]args)throwsException{ServerSocketserverSocket=newServerSocket(80);while(true){finalSocketconn=serverSocket.accept();Runnabletask=newRunnable(){@Overridepublicvoidrun(){handleRequest(conn);}};exec.execute(task);}}}另外可以实现Executor来控制是并发还是并行,如下code:/***执行提交的Runnable任务的对象。*此接口提供了一种方法,可以将任务提交与每个任务将如何运行的机制(包括线程使用、调度等细节)分离。*通常使用Executor而不是显式创建线程。***@authorrenchunxiao**/publicclassExecutorDemo{publicstaticvoidmain(String[]args){Executorexecutor=newThreadExecutor();executor.execute(newRunnable(){@Overridepublicvoidrun(){//dosomething}});Executorexecutor2=newSerialExecutor();executor2.execute(newRunnable(){@Overridepublicvoidrun(){//dosomething}});}}/***创建线程执行command**@authorrenchunxiao**/classThreadExecutorimplementsExecutor{@Overridepublicvoidexecute(Runnablecommand){newThread(command).start();}}/***串口执行命令**@authorrenchunxiao**/classSerialExecutorimplementsExecutor{@Overridepublicvoidexecute(Runnablecommand){command.run();}}线程池线程池是线程的资源池,它可以通过Executors中的静态工厂方法创建线程池。新的固定线程池。创建定长线程池,每提交一个任务就创建一个线程,直到达到线程池的最大数量,线程池的大小不会改变。新的单线程执行器。单线程池。新缓存线程池。根据任务大小而变化的线程池。新的调度线程池。创建一个固定长度的线程池以延迟或计划的方式执行任务。JVM只有在所有非daemon线程都终止后才会退出,所以如果Executor不能正常关闭,JVM就无法结束。为了解决执行服务的生命周期问题,有一个扩展Executor接口的新接口ExecutorService。publicinterfaceExecutorServiceextendsExecutor{voidshutdown();ListshutdownNow();booleanisShutdown();booleanisTerminated();booleanawaitTermination(longtimeout,TimeUnitunit)throwsInterruptedException;Futuresubmit(Callabletask);Future提交(Runnabletask,Tresult);未来提交(Runnabletask);List>invokeAll(Collection>tasks)throwsInterruptedException;List>invokeAll(Collection>tasks,longtimeout,TimeUnitunit)throwsInterruptedException;TinvokeAny(Collection>tasks)throwsInterruptedException,ExecutionException;TinvokeAny(Collection>tasks,longtimeout,TimeUnitunit)throwsInterruptedException,ExecutionException,TimeoutException;}ExecutorService生命周期有三种状态:运行、关闭、已终止。ExecutorService在最初创建时正在运行。shutdown方法优雅关闭:不接受新的任务,等待已经执行的任务完成(包括还没有开始的)。shutdownNow方法将执行粗略关闭:它将尝试取消所有正在运行的任务,并且不会启动队列中尚未启动的任何任务。所有任务执行完毕后,进入终止状态。Callable和FutureExecutor框架使用Runnable作为基本任务表示。Runnable是一个有限的抽象,它的run方法不能返回值并抛出检查异常。很多任务其实都是延迟计算,比如查询数据库,从网络获取资源。对于这些任务,Callable是一个更好的抽象,它假定调用将返回一个值,并可能抛出异常。Executors执行的任务有四个生命周期阶段:创建、提交、开始和完成。由于有些任务耗时较长,可能要取消,所以在Executor框架中,可以取消已经提交但还没有开始的任务。Future代表了一个任务的生命周期,并提供了相应的方法来判断是否已经完成或取消,以及获取任务的结果和取消任务等。