原文地址:http://www.iteye.com/topic/628507
关于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.<span style="white-space: normal;"> </span>
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 business
- try {
- 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;
- }