Java 多线程笔记1-Thread.interrupt/interrupted/isInterrupted

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}}
   *【landon认为因阻塞的线程被interrupt后,虽然是收到了异常,但是却中断了阻塞,其实是可以继续运行的!所以会清除中断状态】
* </pre>
  * <pre>
  *  if (Thread.interrupted())  // Clears interrupted status!
  *      throw new InterruptedException();
  * </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.

你可能感兴趣的:(Java 多线程笔记1-Thread.interrupt/interrupted/isInterrupted)