理解java多线程中ExecutorService使用
java.util.concurrent包里提供了关于多线程操作的类,平常用的比较多的是ExecutorService及其实现类(如ThreadPoolExecutor等),Executor,Executors,Future,Callable等
1.ExecutorService(继承自Executor)接口:提供了一些异步的多线程操作方法,如execute(),submit(),shutdown(),shutdownNow()等
2.Executor接口:执行提交的任务(线程),只有一个方法execute(Runnablea)
2.Executors类:提供了一些工厂方法和一些公共方法来操作Executor子类和ThreadFactory等,如newXXX(),xxxThreadFactory()等
3.Futrue接口:代表了线程执行结果,提供了获取线程执行结果和取消线程的方法,如get(),cancle()等
4.Callable接口:JDK1.5提供的有返回值的线程执行新接口
对ExecutorService和Future的理解做简单记录
代码:
publicclassMain{ privatestaticintcount=0; publicstaticvoidmain(String[]args){ List<Future>resultList=newLinkedList<>(); /** *Executors.newCachedThreadPool()创建一个线程缓存池,若60s中线程没有被使用,则会停止线程并从缓存池中移除 *Executors.newScheduledThreadPool()创建一个固定容量的线程池,里边的线程按照设定的调度时间执行 *Executors.newFixedThreadPool()拥有固定容量的线程缓存池 *Executors.newSingleThreadExecutor()容量为一的线程缓存池,只会有一个线程 */ ExecutorServiceexecutorService=Executors.newCachedThreadPool(); for(inti=0;i<10;i++){ Futurefuture=executorService.submit(newCallable<String>(){ @Override publicStringcall(){ try{ System.out.println(Thread.currentThread().getName()); Thread.sleep(5000); }catch(InterruptedExceptione){ e.printStackTrace(); } intcount=Main.count; System.out.println(Thread.currentThread().getName()+"..startMaincount:..."+count); Main.count=++count; System.out.println(Thread.currentThread().getName()+"..endMaincount:..."+Main.count); returnThread.currentThread().getName(); } }); resultList.add(future); } executorService.shutdown(); for(Futurefuture:resultList){ try{ System.out.println(future.get()+"..isover..."); }catch(InterruptedExceptione){ e.printStackTrace(); }catch(ExecutionExceptione){ e.printStackTrace(); } } System.out.println("mainthreadend..."); } }
输出:
pool-1-thread-1 pool-1-thread-2 pool-1-thread-3 pool-1-thread-4 pool-1-thread-5 pool-1-thread-6 pool-1-thread-7 pool-1-thread-8 pool-1-thread-9 pool-1-thread-10 pool-1-thread-1..startMaincount:...0 pool-1-thread-2..startMaincount:...0 pool-1-thread-3..startMaincount:...1 pool-1-thread-2..endMaincount:...1 pool-1-thread-1..endMaincount:...1 pool-1-thread-3..endMaincount:...2 pool-1-thread-1..isover... pool-1-thread-2..isover... pool-1-thread-4..startMaincount:...2 pool-1-thread-3..isover... pool-1-thread-4..endMaincount:...3 pool-1-thread-4..isover... pool-1-thread-5..startMaincount:...3 pool-1-thread-5..endMaincount:...4 pool-1-thread-5..isover... pool-1-thread-6..startMaincount:...4 pool-1-thread-6..endMaincount:...5 pool-1-thread-6..isover... pool-1-thread-7..startMaincount:...5 pool-1-thread-7..endMaincount:...6 pool-1-thread-7..isover... pool-1-thread-8..startMaincount:...6 pool-1-thread-8..endMaincount:...7 pool-1-thread-8..isover... pool-1-thread-9..startMaincount:...7 pool-1-thread-9..endMaincount:...8 pool-1-thread-9..isover... pool-1-thread-10..startMaincount:...8 pool-1-thread-10..endMaincount:...9 pool-1-thread-10..isover... mainthreadend...//主线程在所有线程执行完成后结束
控制台在等待5秒后打印出上边的输出结果,原因是所有的线程启动的时候是一个并发操作,都会去等待5秒,所以整体看来只等了5秒,这是一个并发操作
总结:
1.ExecutorService提供的execute()方法和submit()方法的区别:
a.execute()方法只接受Runnable类型的实例,所以不能拿到返回值,也不能动态获取线程执行的情况
b.submit()方法接受Runnable和Callable实例,会返回Future实例,Future实例的get()方法可以获取线程执行返回值,并能抛出线程执行异常。所以如果要获取线程执行返回的结果,并能处理线程执行时可能出现的异常,或者想中途取消线程执行时可以使用submit()方法
2.通过输出可以看到main方法(主线程)在所有线程执行完成后结束,原因:
a.通过submit()方法获取Future实例,并通过Future实例的get()方法获取线程返回结果,而Future实例的get()方法会等待线程执行完毕才会返回,所以main方法会等待所有子线程结束才会结束
b.若去掉上边红色标注的for循环,则main方法(主线程)会提前结束,而不会等待所有子线程结束
补充:
1.多个线程并发执行时,若其中某一个线程出现了异常并且没有被处理,则该线程会自动停止执行,但其他线程还是会正常执行,这就是为什么tomcat请求出现异常时,tomcat还可以继续提供服务的原因。
2.tomcat提供了线程池和等待池,每一个请求过来都会重新启动一个新的线程处理该请求,若线程池中线程用完,再来请求的时候就会放到等待池中等待,当其中有线程释放回线程池中时,就会为等待池中的请求分配线程处理请求。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。