ExecutorService,也不是想象中的神

原文地址:http://www.iteye.com/topic/628507

关于ExecutorService好用的方面就不说了,effective java里面是强烈推荐使用Executor代替自己管理Thread。

e.g.

 

Java代码   收藏代码
  1. public static void startReceiver() {  
  2.     ExecutorService pool = Executors.newFixedThreadPool(rec_thread_count);  
  3.     pool.execute(new MsgQReceiver());  
  4. }  
 

 

下面看看今天我郁闷的地方:

 

 1.JDK doc里面描述的线程池关闭方法:先暂停接受新任务进来,然后terminate运行中的线程。看起来确实是一个非常完美的方案。

 

Java代码   收藏代码
  1. void shutdownAndAwaitTermination(ExecutorService pool) {  
  2.    pool.shutdown(); // Disable new tasks from being submitted  
  3.    try {  
  4.      // Wait a while for existing tasks to terminate  
  5.      if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {  
  6.        pool.shutdownNow(); // Cancel currently executing tasks  
  7.        // Wait a while for tasks to respond to being cancelled  
  8.        if (!pool.awaitTermination(60, TimeUnit.SECONDS))  
  9.            System.err.println("Pool did not terminate");  
  10.      }  
  11.    } catch (InterruptedException ie) {  
  12.      // (Re-)Cancel if current thread also interrupted  
  13.      pool.shutdownNow();  
  14.      // Preserve interrupt status  
  15.      Thread.currentThread().interrupt();  
  16.    }  
  17.  }  

 

2.分析里面的shutdownNow()实现,发现居然是用的thread.interrupt()。

 

Java代码   收藏代码
  1.    public List<Runnable> shutdownNow() {  
  2.        /* 
  3.         * shutdownNow differs from shutdown only in that 
  4.         * 1. runState is set to STOP, 
  5.         * 2. all worker threads are interrupted, not just the idle ones, and 
  6.         * 3. the queue is drained and returned. 
  7.         */  
  8. SecurityManager security = System.getSecurityManager();  
  9. if (security != null)  
  10.            security.checkPermission(shutdownPerm);  
  11.   
  12.        final ReentrantLock mainLock = this.mainLock;  
  13.        mainLock.lock();  
  14.        try {  
  15.            if (security != null) { // Check if caller can modify our threads  
  16.                for (Worker w : workers)  
  17.                    security.checkAccess(w.thread);  
  18.            }  
  19.   
  20.            int state = runState;  
  21.            if (state < STOP)  
  22.                runState = STOP;  
  23.   
  24.            try {  
  25.                for (Worker w : workers) {  
  26.                    w.interruptNow();  
  27.                }  
  28.            } catch (SecurityException se) { // Try to back out  
  29.                runState = state;  
  30.                // tryTerminate() here would be a no-op  
  31.                throw se;  
  32.            }  
  33.   
  34.            List<Runnable> tasks = drainQueue();  
  35.            tryTerminate(); // Terminate now if pool and queue empty  
  36.            return tasks;  
  37.        } finally {  
  38.            mainLock.unlock();  
  39.        }  
  40.    }  

 

 

   3.在jdk5之后,线程的stop()方法已经被不推荐使用,并且没有替代品。文档上如是说:

建议线程通过里面设置boolean runflag,不停轮询该变量来确定是否继续执行(具体做法可以参考下面我的demo)

 

Html代码   收藏代码
  1. Deprecated. This method is inherently unsafe. Stopping a thread with Thread.stop causes it to   
Html代码   收藏代码
  1. unlock all of the monitors that it has locked 。 Many uses of stop should be replaced by code that  
Html代码   收藏代码
  1. simply modifies some variable to indicate that the target thread should stop running.   
Html代码   收藏代码
  1. The target thread should check this variable regularly, and return from its run method in an orderly  
Html代码   收藏代码
  1. fashion if the variable indicates that it is to stop running. If the target thread waits for long periods  
Html代码   收藏代码
  1. (on a condition variable, for example), the interrupt method should be used to interrupt the wait.<span style="white-space: normal;"> </span>  

 

 

 

 4.恰不碰巧,我放进去的thread本身就会有很多sleep()操作,

 

sleep会在本线程被interrupt的时候抛异常,

 

Java代码   收藏代码
  1. /**  
  2.  * Causes the currently executing thread to sleep (temporarily cease  
  3.  * execution) for the specified number of milliseconds, subject to  
  4.  * the precision and accuracy of system timers and schedulers. The thread  
  5.  * does not lose ownership of any monitors. 
  6.  * 
  7.  * @param      millis   the length of time to sleep in milliseconds. 
  8.  * @exception  InterruptedException if any thread has interrupted 
  9.  *             the current thread.  The <i>interrupted status</i> of the 
  10.  *             current thread is cleared when this exception is thrown. 
  11.  * @see        Object#notify() 
  12.  */  
  13. public static native void sleep(long millis) throws InterruptedException;  

 

 

interrupte方法如是说明:

If this thread is blocked in an invocation of the wait()wait(long), or wait(long, int) methods of the Object class, or of the join()join(long)join(long, int)sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

 

 

 

那么使用ExecutorService来关闭我下面这些线程,碰到可能都会是抛出InterruptedException 。走到异常流程并非

优雅的方式,也就失去了步骤1中的意义。

 

Java代码   收藏代码
  1. while(runflag)  {  
  2.         //do your business  
  3.         try {  
  4.             Thread.sleep(30);  
  5.         } catch (InterruptedException e) {  
  6.             logger.error("msg收取线程sleep异常", e);  
  7.         }  
  8.   
  9.     } else if (stRet.iRet == -1) { // 没收到消息!!  
  10.         try {  
  11.             Thread.sleep(1000);  
  12.         } catch (InterruptedException e) {  
  13.             logger.error("msg收取线程sleep异常", e);  
  14.         }  
  15.     } else {  
  16.         try {  
  17.             Thread.sleep(2000);  
  18.         } catch (InterruptedException e) {  
  19.             logger.error("msg收取线程sleep异常", e);  
  20.         }  
  21. }             

 

end:

于是乎,只好回归原始.自己通过改变runflag来友好的关闭线程。

Java代码   收藏代码
  1.     public static void startReceiver() {  
  2.           
  3.         for(int i=0;i<rec_thread_count;i++) {  
  4.             MsgQReceiver rec = new MsgQReceiver();  
  5.             group.add(rec);  
  6.             rec.start();  
  7.         }  
  8. //      ExecutorService pool = Executors.newFixedThreadPool(rec_thread_count);  
  9. //      pool.execute(new MsgQReceiver());  
  10.     }  
 

Java代码   收藏代码
  1. /** 
  2.  * 终止消息接收线程组 
  3.  */  
  4. public static void stopReceiver() {  
  5.       
  6.     if(group.size()>0) {  
  7.         for(MsgQReceiver rec : group) {  
  8.             rec.runflag = false;  
  9.         }  
  10.     }  
  11.       
  12.     group = null;  
  13.       }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值