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.
posted on 2013-12-06 17:11
landon 阅读(2030)
评论(0) 编辑 收藏 所属分类:
Program