理解java多线程中ExecutorService使用
java.util.concurrent包里提供了关于多线程操作的类,平常用的比较多的是executorservice及其实现类(如threadpoolexecutor等),executor,executors,future,callable等
1. executorservice(继承自executor)接口:提供了一些异步的多线程操作方法,如execute(), submit(), shutdown(), shutdownnow()等
2. executor接口:执行提交的任务(线程),只有一个方法 execute(runnable a)
2. executors类: 提供了一些工厂方法和一些公共方法来操作executor子类和threadfactory等,如newxxx(),xxxthreadfactory()等
3. futrue接口:代表了线程执行结果,提供了获取线程执行结果和取消线程的方法,如get(),cancle()等
4. callable接口:jdk1.5提供的有返回值的线程执行新接口
对executorservice和future的理解做简单记录
代码:
public class main { private static int count = 0; public static void main(string[] args){ list<future> resultlist = new linkedlist<>(); /** * executors.newcachedthreadpool() 创建一个线程缓存池,若60s中线程没有被使用,则会停止线程并从缓存池中移除 * executors.newscheduledthreadpool() 创建一个固定容量的线程池,里边的线程按照设定的调度时间执行 * executors.newfixedthreadpool() 拥有固定容量的线程缓存池 * executors.newsinglethreadexecutor() 容量为一的线程缓存池,只会有一个线程 */ executorservice executorservice = executors.newcachedthreadpool(); for(int i=0; i<10; i++){ future future = executorservice.submit(new callable<string>() { @override public string call() { try { system.out.println(thread.currentthread().getname()); thread.sleep(5000); } catch (interruptedexception e) { e.printstacktrace(); } int count = main.count; system.out.println(thread.currentthread().getname() + "..start main count:..." + count); main.count = ++count; system.out.println(thread.currentthread().getname() + "..end main count:..." + main.count); return thread.currentthread().getname(); } }); resultlist.add(future); } executorservice.shutdown(); for(future future: resultlist){ try { system.out.println(future.get() + "..is over..."); } catch (interruptedexception e) { e.printstacktrace(); } catch (executionexception e) { e.printstacktrace(); } } system.out.println("main thread end..."); } }
输出:
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..start main count:...0 pool-1-thread-2..start main count:...0 pool-1-thread-3..start main count:...1 pool-1-thread-2..end main count:...1 pool-1-thread-1..end main count:...1 pool-1-thread-3..end main count:...2 pool-1-thread-1..is over... pool-1-thread-2..is over... pool-1-thread-4..start main count:...2 pool-1-thread-3..is over... pool-1-thread-4..end main count:...3 pool-1-thread-4..is over... pool-1-thread-5..start main count:...3 pool-1-thread-5..end main count:...4 pool-1-thread-5..is over... pool-1-thread-6..start main count:...4 pool-1-thread-6..end main count:...5 pool-1-thread-6..is over... pool-1-thread-7..start main count:...5 pool-1-thread-7..end main count:...6 pool-1-thread-7..is over... pool-1-thread-8..start main count:...6 pool-1-thread-8..end main count:...7 pool-1-thread-8..is over... pool-1-thread-9..start main count:...7 pool-1-thread-9..end main count:...8 pool-1-thread-9..is over... pool-1-thread-10..start main count:...8 pool-1-thread-10..end main count:...9 pool-1-thread-10..is over... main thread end... //主线程在所有线程执行完成后结束
控制台在等待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提供了线程池和等待池,每一个请求过来都会重新启动一个新的线程处理该请求,若线程池中线程用完,再来请求的时候就会放到等待池中等待,当其中有线程释放回线程池中时,就会为等待池中的请求分配线程处理请求。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。