首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

转载:Java 多线程札记1-Thread.interrupt/interrupted/isInterrupted

2014-01-08 
转载:Java 多线程笔记1-Thread.interrupt/interrupted/isInterrupted原文出处:http://www.blogjava.net/la

转载:Java 多线程笔记1-Thread.interrupt/interrupted/isInterrupted
原文出处:http://www.blogjava.net/landon/archive/2013/12/06/407294.html

Java 多线程笔记1-Thread.interrupt/interrupted/isInterrupted
1.很多人经常会用错interrupt方法,直接看例子
package com.landon.mavs.example.concurrent;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
*
* interrupt容易使用出错的例子
*
* <pre>
* 1.如何结束BadRunnable这样的任务.即没有任务结束条件来保证可以正常关闭它.使用interrupt没有作用,其不会中断正在运行的线程
* 2.结论:任务最好不要这样写,否则无法正常安全的关闭线程.通常需要在while()中指定任务结束条件如设置volatile变量或者判断当前线程是否已中断等或者通过投递结束消息方式(消息队列)等
* </pre>
*
* <p>
* <a href=
* "http://docs.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html"
* >为何Thread#stop/resume/suspend被弃用</a>
* <p>
*
* @author landon
*
*/
public class InterruptePuzzleExample {
    private static final Logger LOGGER = LoggerFactory
            .getLogger(InterruptePuzzleExample.class);

    public static void main(String[] args) throws Throwable {

        // Thread thread = new Thread(new BadRunnable());

        // thread.start();
        // 执行interrupt,试图终止无限循环的任务-徒劳
        // thread.interrupt();

        VolatileRunnable volatileTask = new VolatileRunnable();
        Thread volatileThread = new Thread(volatileTask);
        volatileThread.start();

        // 主线程暂停5s
        Thread.sleep(5 * 1000);
        // 停止任务,结束volatileThread,在主线程置stopFlag(所以用volatile)
        volatileTask.stop();

        LOGGER.debug("VolatileRunnable end.");

        Thread thread2 = new Thread(new InterruptedRunnbale());
        thread2.start();

        // 主线程暂停1秒
        Thread.sleep(1 * 1000);
        // 调用interrupte结束任务->直接中断处于sleep的任务
        thread2.interrupt();

        LOGGER.debug("main_thread2 isInterrupted:" + thread2.isInterrupted());

        QueueThread qt = new QueueThread();
        qt.start();

        for (int i = 1; i < 5; i++) {
            qt.offerMessage(new QueueMessage(i));
        }

        // 准备停止qt
        qt.prepareDispose();

    }

    private static class BadRunnable implements Runnable {

        @Override
        public void run() {
            LOGGER.debug("BadRunnable begin.");

            // 无限循环
            while (true) {
            }
        }

    }

    private static class VolatileRunnable implements Runnable {
        // 指定volatile(更新即可视) 停止标识
        private volatile boolean stopFlag;

        public void stop() {
            stopFlag = true;
        }

        @Override
        public void run() {
            LOGGER.debug("VolatileRunnable begin.");

            while (!stopFlag) {
            }
        }
    }

    private static class InterruptedRunnbale implements Runnable {

        @Override
        public void run() {
            LOGGER.debug("InterruptedRunnbale begin.");

            // 这里判断调用当前是否已被打断做判断
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    // 用sleep替代业务逻辑的耗时,可被打断
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    LOGGER.debug("InterruptedRunnbale is interrupted.");

                    // 参考Interrupt
                    // API.类似调用如wait/join/sleep等方法时会收到InterruptedException且中断状态被清除
                    LOGGER.debug("after catch InterruptedException,thread2 isInterrupted:"
                            + Thread.currentThread().isInterrupted());
                    // 因为中断状态被清除了.所以这次要再次调用interrupt.设置中断状态,然后任务从循环跳出.线程结束
                    Thread.currentThread().interrupt();
                    LOGGER.debug("after again execute interrupt,thread2 isInterrupted:"
                            + Thread.currentThread().isInterrupted());
                }
            }
        }
    }

    private static class QueueThread extends Thread {
        // 阻塞消息队列
        private LinkedBlockingQueue<QueueMessage> queue = new LinkedBlockingQueue<InterruptePuzzleExample.QueueMessage>();
        // 因为这里通过投递内部消息方式,即在内部单线程执行.所以不用volatile
        private boolean stopFlag;

        @Override
        public void run() {
            LOGGER.debug("QueueThread begin.");

            while (!stopFlag) {
                try {
                    QueueMessage msg = queue.take();

                    if (msg != null) {
                        LOGGER.debug("QueueThread process msg:" + msg);

                        // -1表示停止消息(注:因为是QueueMessage内部使用,可以直接访问private属性)
                        if (msg.msgType == -1) {
                            dispose();
                        }
                    }

                } catch (InterruptedException e) {
                    LOGGER.debug("QueueMessage is interrupted.take is notify.");
                }
            }
        }

        public void offerMessage(QueueMessage msg) {
            queue.offer(msg);
        }

        public void dispose() {
            stopFlag = true;
            // 这里interrupt可省略,因为既然执行到了dispose,则此时一定未阻塞
            // interrupt();
        }

        // 准备销毁,由外部线程进行调用
        public void prepareDispose() {
            LOGGER.debug("QueueThread prepare dispose.");
            offerMessage(new QueueMessage(-1));
        }
    }

    private static class QueueMessage {
        // 消息类型
        private int msgType;

        public QueueMessage(int type) {
            msgType = type;
        }

        @Override
        public String toString() {
            return "QueueMessage [msgType=" + msgType + "]";
        }

    }
}



2.很多人经常分不清interrupted和isInterrupted两个方法的区别,看例子
package com.landon.mavs.example.concurrent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
*
* 使用Thread#interrupted/Thread#isInterrupted
*
* <pre>
* 1.个人认为interrupted方法是返回之前的中断状态并清除中断状态 2.而isInterrupted只是返回线程的中断状态而已
* 3.而对于interrupt方法
* ,对于诸如可抛出InterruptedException的一些方法,线程收到InterruptedException后会清除中断状态
* ;反之则会设置状态中断{仔细参考Thread#interrupt的api doc}{@link InterruptThread3}}
* </pre>
*
* <pre>
* public boolean isInterrupted() {
*     return isInterrupted(false);
* }
*
* 静态方法->针对当前调用线程
* public static boolean interrupted() {
*     return currentThread().isInterrupted(true);
* }
*
* private native boolean isInterrupted(boolean ClearInterrupted);
* </pre>
*
* @author landon
*
*/
public class ThreadInterruptedExample {
    private static final Logger LOGGER = LoggerFactory
            .getLogger(ThreadInterruptedExample.class);

    public static void main(String[] args) throws Exception {
        InterruptThread it = new InterruptThread();
        it.start();

        InterruptThread2 it2 = new InterruptThread2();
        it2.start();

        InterruptThread3 it3 = new InterruptThread3();
        // 此时it3阻塞在wait方法内
        it3.start();
        // 在外部调用iterrupt->it3收到InterruptedException->中断状态清除
        it3.interrupt();

        // true,因为这个是主线程调用的.所以此时it3还未被清除中断状态
        LOGGER.debug("it3.isInterrupted:" + it3.isInterrupted());
        // 做了一个等待.
        Thread.sleep(3 * 1000);
        // false,此时it3的中断状态已经被清楚
        LOGGER.debug("it3.isInterrupted:" + it3.isInterrupted());
    }

    private static class InterruptThread extends Thread {
        @Override
        public void run() {
            // false
            LOGGER.debug("InterruptThread before interrupt.#interrupted:"
                    + interrupted());
            // false
            LOGGER.debug("InterruptThread before interrupt.#isInterrupted:"
                    + isInterrupted());

            // 调用interrupt,这里直接设置了中断状态
            LOGGER.debug("InterruptThread execute interrupt.");
            interrupt();

            // true
            // 调用了#interrupt->#interrupted返回true->由下面的输出可以看到,其清除了中断状态,所以下面的#isInterrupted返回了false
            LOGGER.debug("InterruptThread after interrupt.#interrupted:"
                    + interrupted());
            // false
            LOGGER.debug("InterruptThread after interrupt.#isInterrupted:"
                    + isInterrupted());
        }
    }

    private static class InterruptThread2 extends Thread {
        @Override
        public void run() {
            // false
            LOGGER.debug("InterruptThread2 before interrupt.#interrupted:"
                    + interrupted());
            // false
            LOGGER.debug("InterruptThread2 before interrupt.#isInterrupted:"
                    + isInterrupted());

            // 调用interrupt
            LOGGER.debug("InterruptThread2 execute interrupt.");
            interrupt();

            // true 这里#interrupt#->isInterrupted->返回true,即该方法不影响线程的中断状态
            LOGGER.debug("InterruptThread2 after interrupt.#isInterrupted:"
                    + isInterrupted());

            // true 这里#interrupted依然返回true并清除了中断状态.所以下面的输出返回false
            LOGGER.debug("InterruptThread2 after interrupt.#interrupted:"
                    + interrupted());

            // false
            LOGGER.debug("InterruptThread2.#isInterrupted:" + isInterrupted());

            // false 这里再次调用#interrupted->返回了false.因为此时的状态状态已经为false了
            LOGGER.debug("InterruptThread2.#interrupted:" + interrupted());

        }
    }

    private static class InterruptThread3 extends Thread {
        private final Object lock = new Object();

        @Override
        public void run() {
            synchronized (lock) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    LOGGER.debug("InterruptThread3#wait,is interrupted..");
                    // false
                    LOGGER.debug("InterruptThread3#wati,receive InterruptedException.#isInterrupted:"
                            + isInterrupted());
                }
            }
        }
    }
}



3.总结:通过代码的方式简单的总结了线程的interrupt,interrupted,isInterrupted三个方法.另外还提供了几个正确结束线程的简单方法demo.

热点排行