首先,根据其他文章提到的,我也实验了的Runnable跟Callable的差别:
1)Callable接口的call()方法有返回值,这样方便处理“需要将一个对象加工并返回”的需求(Runnable的run()没有返回值,但可以通过回调的方式在run()内部解决);
2)都使用ExecutorService来submit()时,均返回Future,但前者的future.get()为空,后者可以有内容;
试验一下Executors.newFixedThreadPool(), 代码如下:
public classtestExecutorShutdown{public static voidmain(String[] args) throws InterruptedException, ExecutionException{
ExecutorService executor= Executors.newFixedThreadPool(10);
executor.submit(newCallableA(executor));
}
}class CallableA implements Callable{classnewRunnable implements Runnable{private intid;public newRunnable(intid){this.id =id;
}
@Overridepublic voidrun() {
System.out.println("newRunnable:"+id+"executed; Thread hashCode:"+Thread.currentThread().hashCode());
}
}
ExecutorService executor= null;publicCallableA(ExecutorService executor){this.executor =executor;
}
@OverridepublicObject call() {for(int i=0; i<100; i++){
executor.submit(newnewRunnable(i));
}return null;
}
}
结果:
newRunnable:9 executed; Thread hashCode: 777173972
newRunnable:10 executed; Thread hashCode: 777173972
newRunnable:3 executed; Thread hashCode: 622087230
newRunnable:12 executed; Thread hashCode: 622087230
newRunnable:7 executed; Thread hashCode: 348776228
newRunnable:13 executed; Thread hashCode: 622087230
newRunnable:14 executed; Thread hashCode: 622087230
newRunnable:6 executed; Thread hashCode: 948531615
newRunnable:17 executed; Thread hashCode: 948531615
newRunnable:18 executed; Thread hashCode: 948531615
newRunnable:19 executed; Thread hashCode: 948531615
newRunnable:20 executed; Thread hashCode: 948531615 ......
这里只贴了结果的一部分,可以看到newFixedThreadPool会把一个Runnable或Callable任务拆分给最多n个(new的时候定义的)线程来做,且各做一部分,不会重复,但顺序不一定。
另外,我尝试了在run()方法中,插入if(i==50){executor.shutdownNow(); System.out.pringln(...); //或shutdown()}, 结果还是有其他的线程的内容打印出来,这里说明了两个问题:
1)任务的拆分是submit()方法(或execute()方法)一开始调用时就做好的,然后没有特定顺序地同时开始,这印证了上一部分的结论,更是由于此,shutdown()和shutdownNow()的执行点if(i==50)其实是没有意义的,因为什么时候i==50的那个newRunnable线程是不一定的,且就算执行了,System.out.println()方法打印出结果的时刻并不准确代表了所有线程的执行进度,可能shutdownNow()之前很多线程已经开启,只是打印到控制台比较晚,才出现了上述结果;
2)另外,文档给出shutdownNow()方法的解释是“对于已经开始执行的线程,不一定能彻底shutdown”,原文如下,说明这种方法来完全shutdown线程池中的线程是不靠谱的:
shutdownNow
ListshutdownNow()
Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.
This method does not waitfor actively executing tasks to terminate. Use awaitTermination to dothat.
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.
一点想法:
1.如果不使用executor这种线程池的时候,多线程编程的一般思路是首先通过实现runnable或thread借口,描述一个具体的任务,然后多个线程,各执行一个(互不相同)的任务,而executor这种线程池的作用是通过内建的方法将某一个具体任务拆解,给(由executor维护的)多个线程来执行同一个任务(的不同部分或阶段),从而提升执行单一任务的执行速度(但必然以占用相对而言,更多资源为代价),这是推测哈,要是不看源码并进一步实践,我肯定不好这么笃定。
写的很差哈,一步步简单理解Executor线程池的作用,未完待续。。。