ExecutorService,也不是想象中的神

来源:互联网 发布:便携式医用冷藏箱知乎 编辑:程序博客网 时间:2024/05/21 09:32

 

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

e.g.

 

public static void startReceiver() {ExecutorService pool = Executors.newFixedThreadPool(rec_thread_count);pool.execute(new MsgQReceiver());}
 

 

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

 

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

 

void shutdownAndAwaitTermination(ExecutorService pool) {   pool.shutdown(); // Disable new tasks from being submitted   try {     // Wait a while for existing tasks to terminate     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {       pool.shutdownNow(); // Cancel currently executing tasks       // Wait a while for tasks to respond to being cancelled       if (!pool.awaitTermination(60, TimeUnit.SECONDS))           System.err.println("Pool did not terminate");     }   } catch (InterruptedException ie) {     // (Re-)Cancel if current thread also interrupted     pool.shutdownNow();     // Preserve interrupt status     Thread.currentThread().interrupt();   } }

 

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

 

    public List<Runnable> shutdownNow() {        /*         * shutdownNow differs from shutdown only in that         * 1. runState is set to STOP,         * 2. all worker threads are interrupted, not just the idle ones, and         * 3. the queue is drained and returned.         */SecurityManager security = System.getSecurityManager();if (security != null)            security.checkPermission(shutdownPerm);        final ReentrantLock mainLock = this.mainLock;        mainLock.lock();        try {            if (security != null) { // Check if caller can modify our threads                for (Worker w : workers)                    security.checkAccess(w.thread);            }            int state = runState;            if (state < STOP)                runState = STOP;            try {                for (Worker w : workers) {                    w.interruptNow();                }            } catch (SecurityException se) { // Try to back out                runState = state;                // tryTerminate() here would be a no-op                throw se;            }            List<Runnable> tasks = drainQueue();            tryTerminate(); // Terminate now if pool and queue empty            return tasks;        } finally {            mainLock.unlock();        }    }

 

 

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

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

 

Deprecated. This method is inherently unsafe. Stopping a thread with Thread.stop causes it to 
unlock all of the monitors that it has locked 。 Many uses of stop should be replaced by code that
 simply modifies some variable to indicate that the target thread should stop running. 
The target thread should check this variable regularly, and return from its run method in an orderly
 fashion if the variable indicates that it is to stop running. If the target thread waits for long periods
 (on a condition variable, for example), the interrupt method should be used to interrupt the wait. 

 

 

 

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

 

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

 

    /**     * Causes the currently executing thread to sleep (temporarily cease      * execution) for the specified number of milliseconds, subject to      * the precision and accuracy of system timers and schedulers. The thread      * does not lose ownership of any monitors.     *     * @param      millis   the length of time to sleep in milliseconds.     * @exception  InterruptedException if any thread has interrupted     *             the current thread.  The <i>interrupted status</i> of the     *             current thread is cleared when this exception is thrown.     * @see        Object#notify()     */    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中的意义。

 

while(runflag){//do your businesstry {Thread.sleep(30);} catch (InterruptedException e) {logger.error("msg收取线程sleep异常", e);}} else if (stRet.iRet == -1) { // 没收到消息!!try {Thread.sleep(1000);} catch (InterruptedException e) {logger.error("msg收取线程sleep异常", e);}} else {try {Thread.sleep(2000);} catch (InterruptedException e) {logger.error("msg收取线程sleep异常", e);}}

 

end:

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

public static void startReceiver() {for(int i=0;i<rec_thread_count;i++) {MsgQReceiver rec = new MsgQReceiver();group.add(rec);rec.start();}//ExecutorService pool = Executors.newFixedThreadPool(rec_thread_count);//pool.execute(new MsgQReceiver());}
 

/** * 终止消息接收线程组 */public static void stopReceiver() {if(group.size()>0) {for(MsgQReceiver rec : group) {rec.runflag = false;}}group = null;       }
0 0
原创粉丝点击