java線程阻塞中斷與LockSupport使用介紹
更新時(shí)間:2012年12月03日 14:26:42 作者:
本文將詳細(xì)介紹java線程阻塞中斷和LockSupport的使用,需要了解更多的朋友可以參考下
上周五和周末,工作忙里偷閑,在看java cocurrent中也順便再溫故了一下Thread.interrupt和java 5之后的LockSupport的實(shí)現(xiàn)。
在介紹之前,先拋幾個(gè)問題。
Thread.interrupt()方法和InterruptedException異常的關(guān)系?是由interrupt觸發(fā)產(chǎn)生了InterruptedException異常?
Thread.interrupt()會(huì)中斷線程什么狀態(tài)的工作? RUNNING or BLOCKING?
一般Thread編程需要關(guān)注interrupt中斷不?一般怎么處理?可以用來做什么?
LockSupport.park()和unpark(),與object.wait()和notify()的區(qū)別?
LockSupport.park(Object blocker)傳遞的blocker對(duì)象做什么用?
LockSupport能響應(yīng)Thread.interrupt()事件不?會(huì)拋出InterruptedException異常?
Thread.interrupt()處理是否有對(duì)應(yīng)的回調(diào)函數(shù)?類似于鉤子調(diào)用?
如果你都都能很明確的答上來了,說明你已經(jīng)完全懂Thread.interrupt,可以不用往下看那了。
那如果不清楚的,帶著這幾個(gè)問題,一起來梳理下。
Thread的interrupt處理的幾個(gè)方法:
public void interrupt() : 執(zhí)行線程interrupt事件
public boolean isInterrupted() : 檢查當(dāng)前線程是否處于interrupt
public static boolean interrupted() : check當(dāng)前線程是否處于interrupt,并重置interrupt信息。類似于resetAndGet()
理解:
1. 每個(gè)線程都有一個(gè)interrupt status標(biāo)志位,用于表明當(dāng)前線程是否處于中斷狀態(tài)
2. 一般調(diào)用Thread.interrupt()會(huì)有兩種處理方式
遇到一個(gè)低優(yōu)先級(jí)的block狀態(tài)時(shí),比如object.wait(),object.sleep(),object.join()。它會(huì)立馬觸發(fā)一個(gè)unblock解除阻塞,并throw一個(gè)InterruptedException。
其他情況,Thread.interrupt()僅僅只是更新了status標(biāo)志位。然后你的工作線程通過Thread.isInterrrupted()進(jìn)行檢查,可以做相應(yīng)的處理,比如也throw InterruptedException或者是清理狀態(tài),取消task等。
在interrupt javadoc中描述:
最佳實(shí)踐
IBM上有篇文章寫的挺不錯(cuò)。Java theory and practice: Dealing with InterruptedException , 里面提到了Interrupt處理的幾條最佳實(shí)踐。
Don't swallow interrupts (別吃掉Interrupt,一般是兩種處理: 繼續(xù)throw InterruptedException異常。 另一種就是繼續(xù)設(shè)置Thread.interupt()異常標(biāo)志位,讓更上一層去進(jìn)行相應(yīng)處理。
public class TaskRunner implements Runnable {
private BlockingQueue<Task> queue;
public TaskRunner(BlockingQueue<Task> queue) {
this.queue = queue;
}
public void run() {
try {
while (true) {
Task task = queue.take(10, TimeUnit.SECONDS);
task.execute();
}
}
catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
}
public class TaskRunner implements Runnable {
private BlockingQueue<Task> queue;
public TaskRunner(BlockingQueue<Task> queue) {
this.queue = queue;
}
public void run() {
try {
while (true) {
Task task = queue.take(10, TimeUnit.SECONDS);
task.execute();
}
}
catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
}
Implementing cancelable tasks with Interrupt (使用Thread.interrupt()來設(shè)計(jì)和支持可被cancel的task)
public class PrimeProducer extends Thread {
private final BlockingQueue<BigInteger> queue;
PrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
public void run() {
try {
BigInteger p = BigInteger.ONE;
while (!Thread.currentThread().isInterrupted())
queue.put(p = p.nextProbablePrime());
} catch (InterruptedException consumed) {
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); } // 發(fā)起中斷
}<SPAN style="WHITE-SPACE: normal"> </SPAN>
public class PrimeProducer extends Thread {
private final BlockingQueue<BigInteger> queue;
PrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
public void run() {
try {
BigInteger p = BigInteger.ONE;
while (!Thread.currentThread().isInterrupted())
queue.put(p = p.nextProbablePrime());
} catch (InterruptedException consumed) {
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); } // 發(fā)起中斷
}<SPAN style="WHITE-SPACE: normal"> </SPAN>
注冊(cè)Interrupt處理事件(非正常用法)
一般正常的task設(shè)計(jì)用來處理cancel,都是采用主動(dòng)輪詢的方式檢查Thread.isInterrupt(),對(duì)業(yè)務(wù)本身存在一定的嵌入性,還有就是存在延遲,你得等到下一個(gè)檢查點(diǎn)(誰知道下一個(gè)檢查點(diǎn)是在什么時(shí)候,特別是進(jìn)行一個(gè)socket.read時(shí),遇到過一個(gè)HttpClient超時(shí)的問題)。
來看一下,主動(dòng)拋出InterruptedException異常的實(shí)現(xiàn),借鑒于InterruptibleChannel的設(shè)計(jì),比較取巧。
interface InterruptAble { // 定義可中斷的接口
public void interrupt() throws InterruptedException;
}
abstract class InterruptSupport implements InterruptAble {
private volatile boolean interrupted = false;
private Interruptible interruptor = new Interruptible() {
public void interrupt() {
interrupted = true;
InterruptSupport.this.interrupt(); // 位置3
}
};
public final boolean execute() throws InterruptedException {
try {
blockedOn(interruptor); // 位置1
if (Thread.currentThread().isInterrupted()) { // 立馬被interrupted
interruptor.interrupt();
}
// 執(zhí)行業(yè)務(wù)代碼
bussiness();
} finally {
blockedOn(null); // 位置2
}
return interrupted;
}
public abstract void bussiness() ;
public abstract void interrupt();
// -- sun.misc.SharedSecrets --
static void blockedOn(Interruptible intr) { // package-private
sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
}
}
interface InterruptAble { // 定義可中斷的接口
public void interrupt() throws InterruptedException;
}
abstract class InterruptSupport implements InterruptAble {
private volatile boolean interrupted = false;
private Interruptible interruptor = new Interruptible() {
public void interrupt() {
interrupted = true;
InterruptSupport.this.interrupt(); // 位置3
}
};
public final boolean execute() throws InterruptedException {
try {
blockedOn(interruptor); // 位置1
if (Thread.currentThread().isInterrupted()) { // 立馬被interrupted
interruptor.interrupt();
}
// 執(zhí)行業(yè)務(wù)代碼
bussiness();
} finally {
blockedOn(null); // 位置2
}
return interrupted;
}
public abstract void bussiness() ;
public abstract void interrupt();
// -- sun.misc.SharedSecrets --
static void blockedOn(Interruptible intr) { // package-private
sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
}
}
代碼說明,幾個(gè)取巧的點(diǎn):
位置1:利用sun提供的blockedOn方法,綁定對(duì)應(yīng)的Interruptible事件處理鉤子到指定的Thread上。
位置2:執(zhí)行完代碼后,清空鉤子。避免使用連接池時(shí),對(duì)下一個(gè)Thread處理事件的影響。
位置3:定義了Interruptible事件鉤子的處理方法,回調(diào)InterruptSupport.this.interrupt()方法,子類可以集成實(shí)現(xiàn)自己的業(yè)務(wù)邏輯,比如sock流關(guān)閉等等。
使用:
class InterruptRead extends InterruptSupport {
private FileInputStream in;
@Override
public void bussiness() {
File file = new File("/dev/urandom"); // 讀取linux黑洞,永遠(yuǎn)讀不完
try {
in = new FileInputStream(file);
byte[] bytes = new byte[1024];
while (in.read(bytes, 0, 1024) > 0) {
// Thread.sleep(100);
// if (Thread.interrupted()) {// 以前的Interrupt檢查方式
// throw new InterruptedException("");
// }
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public FileInputStream getIn() {
return in;
}
@Override
public void interrupt() {
try {
in.getChannel().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) throws Exception {
final InterruptRead test = new InterruptRead();
Thread t = new Thread() {
@Override
public void run() {
long start = System.currentTimeMillis();
try {
System.out.println("InterruptRead start!");
test.execute();
} catch (InterruptedException e) {
System.out.println("InterruptRead end! cost time : " + (System.currentTimeMillis() - start));
e.printStackTrace();
}
}
};
t.start();
// 先讓Read執(zhí)行3秒
Thread.sleep(3000);
// 發(fā)出interrupt中斷
t.interrupt();
}
class InterruptRead extends InterruptSupport {
private FileInputStream in;
@Override
public void bussiness() {
File file = new File("/dev/urandom"); // 讀取linux黑洞,永遠(yuǎn)讀不完
try {
in = new FileInputStream(file);
byte[] bytes = new byte[1024];
while (in.read(bytes, 0, 1024) > 0) {
// Thread.sleep(100);
// if (Thread.interrupted()) {// 以前的Interrupt檢查方式
// throw new InterruptedException("");
// }
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public FileInputStream getIn() {
return in;
}
@Override
public void interrupt() {
try {
in.getChannel().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) throws Exception {
final InterruptRead test = new InterruptRead();
Thread t = new Thread() {
@Override
public void run() {
long start = System.currentTimeMillis();
try {
System.out.println("InterruptRead start!");
test.execute();
} catch (InterruptedException e) {
System.out.println("InterruptRead end! cost time : " + (System.currentTimeMillis() - start));
e.printStackTrace();
}
}
};
t.start();
// 先讓Read執(zhí)行3秒
Thread.sleep(3000);
// 發(fā)出interrupt中斷
t.interrupt();
}
jdk源碼介紹:
1. sun提供的鉤子可以查看System的相關(guān)代碼, line : 1125
sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){
public sun.reflect.ConstantPool getConstantPool(Class klass) {
return klass.getConstantPool();
}
public void setAnnotationType(Class klass, AnnotationType type) {
klass.setAnnotationType(type);
}
public AnnotationType getAnnotationType(Class klass) {
return klass.getAnnotationType();
}
public <E extends Enum<E>>
E[] getEnumConstantsShared(Class<E> klass) {
return klass.getEnumConstantsShared();
}
public void blockedOn(Thread t, Interruptible b) {
t.blockedOn(b);
}
});
sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){
public sun.reflect.ConstantPool getConstantPool(Class klass) {
return klass.getConstantPool();
}
public void setAnnotationType(Class klass, AnnotationType type) {
klass.setAnnotationType(type);
}
public AnnotationType getAnnotationType(Class klass) {
return klass.getAnnotationType();
}
public <E extends Enum<E>>
E[] getEnumConstantsShared(Class<E> klass) {
return klass.getEnumConstantsShared();
}
public void blockedOn(Thread t, Interruptible b) {
t.blockedOn(b);
}
});
2. Thread.interrupt()
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(); //回調(diào)鉤子
return;
}
}
interrupt0();
}
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(); //回調(diào)鉤子
return;
}
}
interrupt0();
}
更多
更多關(guān)于Thread.stop,suspend,resume,interrupt的使用注意點(diǎn),可以看一下sun的文檔,比如http://download.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
最后來解答一下之前的幾個(gè)問題:
問題1: Thread.interrupt()方法和InterruptedException異常的關(guān)系?是由interrupt觸發(fā)產(chǎn)生了InterruptedException異常?
答: Thread.interrupt()只是在Object.wait() .Object.join(), Object.sleep()幾個(gè)方法會(huì)主動(dòng)拋出InterruptedException異常。而在其他的的block常見,只是通過設(shè)置了Thread的一個(gè)標(biāo)志位信息,需要程序自我進(jìn)行處理。
if (Thread.interrupted()) // Clears interrupted status!
throw new InterruptedException();
if (Thread.interrupted()) // Clears interrupted status!
throw new InterruptedException();
問題2:Thread.interrupt()會(huì)中斷線程什么狀態(tài)的工作? RUNNING or BLOCKING?
答:Thread.interrupt設(shè)計(jì)的目的主要是用于處理線程處于block狀態(tài),比如wait(),sleep()狀態(tài)就是個(gè)例子。但可以在程序設(shè)計(jì)時(shí)為支持task cancel,同樣可以支持RUNNING狀態(tài)。比如Object.join()和一些支持interrupt的一些nio channel設(shè)計(jì)。
問題3: 一般Thread編程需要關(guān)注interrupt中斷不?一般怎么處理?可以用來做什么?
答: interrupt用途: unBlock操作,支持任務(wù)cancel, 數(shù)據(jù)清理等。
問題4: LockSupport.park()和unpark(),與object.wait()和notify()的區(qū)別?
答:
1. 面向的主體不一樣。LockSuport主要是針對(duì)Thread進(jìn)進(jìn)行阻塞處理,可以指定阻塞隊(duì)列的目標(biāo)對(duì)象,每次可以指定具體的線程喚醒。Object.wait()是以對(duì)象為緯度,阻塞當(dāng)前的線程和喚醒單個(gè)(隨機(jī))或者所有線程。
2. 實(shí)現(xiàn)機(jī)制不同。雖然LockSuport可以指定monitor的object對(duì)象,但和object.wait(),兩者的阻塞隊(duì)列并不交叉。可以看下測(cè)試?yán)?。object.notifyAll()不能喚醒LockSupport的阻塞Thread.
問題5: LockSupport.park(Object blocker)傳遞的blocker對(duì)象做什么用?
答: 對(duì)應(yīng)的blcoker會(huì)記錄在Thread的一個(gè)parkBlocker屬性中,通過jstack命令可以非常方便的監(jiān)控具體的阻塞對(duì)象.
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker); // 設(shè)置Thread.parkBlocker屬性的值
unsafe.park(false, 0L);
setBlocker(t, null); // 清除Thread.parkBlocker屬性的值
}
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker); // 設(shè)置Thread.parkBlocker屬性的值
unsafe.park(false, 0L);
setBlocker(t, null); // 清除Thread.parkBlocker屬性的值
}
具體LockSupport的javadoc描述也比較清楚,可以看下:
問題6: LockSupport能響應(yīng)Thread.interrupt()事件不?會(huì)拋出InterruptedException異常?
答:能響應(yīng)interrupt事件,但不會(huì)拋出InterruptedException異常。針對(duì)LockSupport對(duì)Thread.interrupte支持,也先看一下javadoc中的描述:
相關(guān)測(cè)試代碼
package com.agapple.cocurrent;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
public class LockSupportTest {
private static LockSupportTest blocker = new LockSupportTest();
public static void main(String args[]) throws Exception {
lockSupportTest();
parkTest();
interruptParkTest();
interruptSleepTest();
interruptWaitTest();
}
/**
* LockSupport.park對(duì)象后,嘗試獲取Thread.blocker對(duì)象,調(diào)用其single喚醒
*
* @throws Exception
*/
private static void lockSupportTest() throws Exception {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() throws Exception {
// 嘗試sleep 5s
System.out.println("blocker");
LockSupport.park(blocker);
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "lockSupportTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(150);
synchronized (blocker) {
Field field = Thread.class.getDeclaredField("parkBlocker");
field.setAccessible(true);
Object fBlocker = field.get(t);
System.out.println(blocker == fBlocker);
Thread.sleep(100);
System.out.println("notifyAll");
blocker.notifyAll();
}
}
/**
* 嘗試去中斷一個(gè)object.wait(),會(huì)拋出對(duì)應(yīng)的InterruptedException異常
*
* @throws InterruptedException
*/
private static void interruptWaitTest() throws InterruptedException {
final Object obj = new Object();
Thread t = doTest(new TestCallBack() {
@Override
public void callback() throws Exception {
// 嘗試sleep 5s
obj.wait();
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "interruptWaitTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
t.interrupt(); // 檢查下在park時(shí),是否響應(yīng)中斷
}
/**
* 嘗試去中斷一個(gè)Thread.sleep(),會(huì)拋出對(duì)應(yīng)的InterruptedException異常
*
* @throws InterruptedException
*/
private static void interruptSleepTest() throws InterruptedException {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() throws Exception {
// 嘗試sleep 5s
Thread.sleep(5000);
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "interruptSleepTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
t.interrupt(); // 檢查下在park時(shí),是否響應(yīng)中斷
}
/**
* 嘗試去中斷一個(gè)LockSupport.park(),會(huì)有響應(yīng)但不會(huì)拋出InterruptedException異常
*
* @throws InterruptedException
*/
private static void interruptParkTest() throws InterruptedException {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() {
// 嘗試去park 自己線程
LockSupport.parkNanos(blocker, TimeUnit.SECONDS.toNanos(5));
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "interruptParkTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
t.interrupt(); // 檢查下在park時(shí),是否響應(yīng)中斷
}
/**
* 嘗試去中斷一個(gè)LockSupport.unPark(),會(huì)有響應(yīng)
*
* @throws InterruptedException
*/
private static void parkTest() throws InterruptedException {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() {
// 嘗試去park 自己線程
LockSupport.park(blocker);
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "parkTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
LockSupport.unpark(t);
t.interrupt();
}
public static Thread doTest(final TestCallBack call) {
return new Thread() {
@Override
public void run() {
File file = new File("/dev/urandom"); // 讀取linux黑洞
try {
FileInputStream in = new FileInputStream(file);
byte[] bytes = new byte[1024];
while (in.read(bytes, 0, 1024) > 0) {
if (Thread.interrupted()) {
throw new InterruptedException("");
}
System.out.println(bytes[0]);
Thread.sleep(100);
long start = System.currentTimeMillis();
call.callback();
System.out.println(call.getName() + " callback finish cost : "
+ (System.currentTimeMillis() - start));
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
}
}
interface TestCallBack {
public void callback() throws Exception;
public String getName();
}
package com.agapple.cocurrent;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
public class LockSupportTest {
private static LockSupportTest blocker = new LockSupportTest();
public static void main(String args[]) throws Exception {
lockSupportTest();
parkTest();
interruptParkTest();
interruptSleepTest();
interruptWaitTest();
}
/**
* LockSupport.park對(duì)象后,嘗試獲取Thread.blocker對(duì)象,調(diào)用其single喚醒
*
* @throws Exception
*/
private static void lockSupportTest() throws Exception {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() throws Exception {
// 嘗試sleep 5s
System.out.println("blocker");
LockSupport.park(blocker);
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "lockSupportTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(150);
synchronized (blocker) {
Field field = Thread.class.getDeclaredField("parkBlocker");
field.setAccessible(true);
Object fBlocker = field.get(t);
System.out.println(blocker == fBlocker);
Thread.sleep(100);
System.out.println("notifyAll");
blocker.notifyAll();
}
}
/**
* 嘗試去中斷一個(gè)object.wait(),會(huì)拋出對(duì)應(yīng)的InterruptedException異常
*
* @throws InterruptedException
*/
private static void interruptWaitTest() throws InterruptedException {
final Object obj = new Object();
Thread t = doTest(new TestCallBack() {
@Override
public void callback() throws Exception {
// 嘗試sleep 5s
obj.wait();
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "interruptWaitTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
t.interrupt(); // 檢查下在park時(shí),是否響應(yīng)中斷
}
/**
* 嘗試去中斷一個(gè)Thread.sleep(),會(huì)拋出對(duì)應(yīng)的InterruptedException異常
*
* @throws InterruptedException
*/
private static void interruptSleepTest() throws InterruptedException {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() throws Exception {
// 嘗試sleep 5s
Thread.sleep(5000);
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "interruptSleepTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
t.interrupt(); // 檢查下在park時(shí),是否響應(yīng)中斷
}
/**
* 嘗試去中斷一個(gè)LockSupport.park(),會(huì)有響應(yīng)但不會(huì)拋出InterruptedException異常
*
* @throws InterruptedException
*/
private static void interruptParkTest() throws InterruptedException {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() {
// 嘗試去park 自己線程
LockSupport.parkNanos(blocker, TimeUnit.SECONDS.toNanos(5));
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "interruptParkTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
t.interrupt(); // 檢查下在park時(shí),是否響應(yīng)中斷
}
/**
* 嘗試去中斷一個(gè)LockSupport.unPark(),會(huì)有響應(yīng)
*
* @throws InterruptedException
*/
private static void parkTest() throws InterruptedException {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() {
// 嘗試去park 自己線程
LockSupport.park(blocker);
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "parkTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
LockSupport.unpark(t);
t.interrupt();
}
public static Thread doTest(final TestCallBack call) {
return new Thread() {
@Override
public void run() {
File file = new File("/dev/urandom"); // 讀取linux黑洞
try {
FileInputStream in = new FileInputStream(file);
byte[] bytes = new byte[1024];
while (in.read(bytes, 0, 1024) > 0) {
if (Thread.interrupted()) {
throw new InterruptedException("");
}
System.out.println(bytes[0]);
Thread.sleep(100);
long start = System.currentTimeMillis();
call.callback();
System.out.println(call.getName() + " callback finish cost : "
+ (System.currentTimeMillis() - start));
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
}
}
interface TestCallBack {
public void callback() throws Exception;
public String getName();
}
最后
發(fā)覺文章越寫越長(zhǎng),那就索性發(fā)到了論壇,大家一起討論下.畢竟文章中描述的都是一些使用層面的東東,并沒有從操作系統(tǒng)或者sun native實(shí)現(xiàn)上去介紹Thread的一些機(jī)制,熟悉這塊的大牛門也可以出來發(fā)表下高見.
在介紹之前,先拋幾個(gè)問題。
Thread.interrupt()方法和InterruptedException異常的關(guān)系?是由interrupt觸發(fā)產(chǎn)生了InterruptedException異常?
Thread.interrupt()會(huì)中斷線程什么狀態(tài)的工作? RUNNING or BLOCKING?
一般Thread編程需要關(guān)注interrupt中斷不?一般怎么處理?可以用來做什么?
LockSupport.park()和unpark(),與object.wait()和notify()的區(qū)別?
LockSupport.park(Object blocker)傳遞的blocker對(duì)象做什么用?
LockSupport能響應(yīng)Thread.interrupt()事件不?會(huì)拋出InterruptedException異常?
Thread.interrupt()處理是否有對(duì)應(yīng)的回調(diào)函數(shù)?類似于鉤子調(diào)用?
如果你都都能很明確的答上來了,說明你已經(jīng)完全懂Thread.interrupt,可以不用往下看那了。
那如果不清楚的,帶著這幾個(gè)問題,一起來梳理下。
Thread的interrupt處理的幾個(gè)方法:
public void interrupt() : 執(zhí)行線程interrupt事件
public boolean isInterrupted() : 檢查當(dāng)前線程是否處于interrupt
public static boolean interrupted() : check當(dāng)前線程是否處于interrupt,并重置interrupt信息。類似于resetAndGet()
理解:
1. 每個(gè)線程都有一個(gè)interrupt status標(biāo)志位,用于表明當(dāng)前線程是否處于中斷狀態(tài)
2. 一般調(diào)用Thread.interrupt()會(huì)有兩種處理方式
遇到一個(gè)低優(yōu)先級(jí)的block狀態(tài)時(shí),比如object.wait(),object.sleep(),object.join()。它會(huì)立馬觸發(fā)一個(gè)unblock解除阻塞,并throw一個(gè)InterruptedException。
其他情況,Thread.interrupt()僅僅只是更新了status標(biāo)志位。然后你的工作線程通過Thread.isInterrrupted()進(jìn)行檢查,可以做相應(yīng)的處理,比如也throw InterruptedException或者是清理狀態(tài),取消task等。
在interrupt javadoc中描述:

最佳實(shí)踐
IBM上有篇文章寫的挺不錯(cuò)。Java theory and practice: Dealing with InterruptedException , 里面提到了Interrupt處理的幾條最佳實(shí)踐。
Don't swallow interrupts (別吃掉Interrupt,一般是兩種處理: 繼續(xù)throw InterruptedException異常。 另一種就是繼續(xù)設(shè)置Thread.interupt()異常標(biāo)志位,讓更上一層去進(jìn)行相應(yīng)處理。
復(fù)制代碼 代碼如下:
public class TaskRunner implements Runnable {
private BlockingQueue<Task> queue;
public TaskRunner(BlockingQueue<Task> queue) {
this.queue = queue;
}
public void run() {
try {
while (true) {
Task task = queue.take(10, TimeUnit.SECONDS);
task.execute();
}
}
catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
}
復(fù)制代碼 代碼如下:
public class TaskRunner implements Runnable {
private BlockingQueue<Task> queue;
public TaskRunner(BlockingQueue<Task> queue) {
this.queue = queue;
}
public void run() {
try {
while (true) {
Task task = queue.take(10, TimeUnit.SECONDS);
task.execute();
}
}
catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
}
Implementing cancelable tasks with Interrupt (使用Thread.interrupt()來設(shè)計(jì)和支持可被cancel的task)
復(fù)制代碼 代碼如下:
public class PrimeProducer extends Thread {
private final BlockingQueue<BigInteger> queue;
PrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
public void run() {
try {
BigInteger p = BigInteger.ONE;
while (!Thread.currentThread().isInterrupted())
queue.put(p = p.nextProbablePrime());
} catch (InterruptedException consumed) {
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); } // 發(fā)起中斷
}<SPAN style="WHITE-SPACE: normal"> </SPAN>
復(fù)制代碼 代碼如下:
public class PrimeProducer extends Thread {
private final BlockingQueue<BigInteger> queue;
PrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
public void run() {
try {
BigInteger p = BigInteger.ONE;
while (!Thread.currentThread().isInterrupted())
queue.put(p = p.nextProbablePrime());
} catch (InterruptedException consumed) {
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); } // 發(fā)起中斷
}<SPAN style="WHITE-SPACE: normal"> </SPAN>
注冊(cè)Interrupt處理事件(非正常用法)
一般正常的task設(shè)計(jì)用來處理cancel,都是采用主動(dòng)輪詢的方式檢查Thread.isInterrupt(),對(duì)業(yè)務(wù)本身存在一定的嵌入性,還有就是存在延遲,你得等到下一個(gè)檢查點(diǎn)(誰知道下一個(gè)檢查點(diǎn)是在什么時(shí)候,特別是進(jìn)行一個(gè)socket.read時(shí),遇到過一個(gè)HttpClient超時(shí)的問題)。
來看一下,主動(dòng)拋出InterruptedException異常的實(shí)現(xiàn),借鑒于InterruptibleChannel的設(shè)計(jì),比較取巧。
復(fù)制代碼 代碼如下:
interface InterruptAble { // 定義可中斷的接口
public void interrupt() throws InterruptedException;
}
abstract class InterruptSupport implements InterruptAble {
private volatile boolean interrupted = false;
private Interruptible interruptor = new Interruptible() {
public void interrupt() {
interrupted = true;
InterruptSupport.this.interrupt(); // 位置3
}
};
public final boolean execute() throws InterruptedException {
try {
blockedOn(interruptor); // 位置1
if (Thread.currentThread().isInterrupted()) { // 立馬被interrupted
interruptor.interrupt();
}
// 執(zhí)行業(yè)務(wù)代碼
bussiness();
} finally {
blockedOn(null); // 位置2
}
return interrupted;
}
public abstract void bussiness() ;
public abstract void interrupt();
// -- sun.misc.SharedSecrets --
static void blockedOn(Interruptible intr) { // package-private
sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
}
}
復(fù)制代碼 代碼如下:
interface InterruptAble { // 定義可中斷的接口
public void interrupt() throws InterruptedException;
}
abstract class InterruptSupport implements InterruptAble {
private volatile boolean interrupted = false;
private Interruptible interruptor = new Interruptible() {
public void interrupt() {
interrupted = true;
InterruptSupport.this.interrupt(); // 位置3
}
};
public final boolean execute() throws InterruptedException {
try {
blockedOn(interruptor); // 位置1
if (Thread.currentThread().isInterrupted()) { // 立馬被interrupted
interruptor.interrupt();
}
// 執(zhí)行業(yè)務(wù)代碼
bussiness();
} finally {
blockedOn(null); // 位置2
}
return interrupted;
}
public abstract void bussiness() ;
public abstract void interrupt();
// -- sun.misc.SharedSecrets --
static void blockedOn(Interruptible intr) { // package-private
sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
}
}
代碼說明,幾個(gè)取巧的點(diǎn):
位置1:利用sun提供的blockedOn方法,綁定對(duì)應(yīng)的Interruptible事件處理鉤子到指定的Thread上。
位置2:執(zhí)行完代碼后,清空鉤子。避免使用連接池時(shí),對(duì)下一個(gè)Thread處理事件的影響。
位置3:定義了Interruptible事件鉤子的處理方法,回調(diào)InterruptSupport.this.interrupt()方法,子類可以集成實(shí)現(xiàn)自己的業(yè)務(wù)邏輯,比如sock流關(guān)閉等等。
使用:
復(fù)制代碼 代碼如下:
class InterruptRead extends InterruptSupport {
private FileInputStream in;
@Override
public void bussiness() {
File file = new File("/dev/urandom"); // 讀取linux黑洞,永遠(yuǎn)讀不完
try {
in = new FileInputStream(file);
byte[] bytes = new byte[1024];
while (in.read(bytes, 0, 1024) > 0) {
// Thread.sleep(100);
// if (Thread.interrupted()) {// 以前的Interrupt檢查方式
// throw new InterruptedException("");
// }
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public FileInputStream getIn() {
return in;
}
@Override
public void interrupt() {
try {
in.getChannel().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) throws Exception {
final InterruptRead test = new InterruptRead();
Thread t = new Thread() {
@Override
public void run() {
long start = System.currentTimeMillis();
try {
System.out.println("InterruptRead start!");
test.execute();
} catch (InterruptedException e) {
System.out.println("InterruptRead end! cost time : " + (System.currentTimeMillis() - start));
e.printStackTrace();
}
}
};
t.start();
// 先讓Read執(zhí)行3秒
Thread.sleep(3000);
// 發(fā)出interrupt中斷
t.interrupt();
}
復(fù)制代碼 代碼如下:
class InterruptRead extends InterruptSupport {
private FileInputStream in;
@Override
public void bussiness() {
File file = new File("/dev/urandom"); // 讀取linux黑洞,永遠(yuǎn)讀不完
try {
in = new FileInputStream(file);
byte[] bytes = new byte[1024];
while (in.read(bytes, 0, 1024) > 0) {
// Thread.sleep(100);
// if (Thread.interrupted()) {// 以前的Interrupt檢查方式
// throw new InterruptedException("");
// }
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public FileInputStream getIn() {
return in;
}
@Override
public void interrupt() {
try {
in.getChannel().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) throws Exception {
final InterruptRead test = new InterruptRead();
Thread t = new Thread() {
@Override
public void run() {
long start = System.currentTimeMillis();
try {
System.out.println("InterruptRead start!");
test.execute();
} catch (InterruptedException e) {
System.out.println("InterruptRead end! cost time : " + (System.currentTimeMillis() - start));
e.printStackTrace();
}
}
};
t.start();
// 先讓Read執(zhí)行3秒
Thread.sleep(3000);
// 發(fā)出interrupt中斷
t.interrupt();
}
jdk源碼介紹:
1. sun提供的鉤子可以查看System的相關(guān)代碼, line : 1125
復(fù)制代碼 代碼如下:
sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){
public sun.reflect.ConstantPool getConstantPool(Class klass) {
return klass.getConstantPool();
}
public void setAnnotationType(Class klass, AnnotationType type) {
klass.setAnnotationType(type);
}
public AnnotationType getAnnotationType(Class klass) {
return klass.getAnnotationType();
}
public <E extends Enum<E>>
E[] getEnumConstantsShared(Class<E> klass) {
return klass.getEnumConstantsShared();
}
public void blockedOn(Thread t, Interruptible b) {
t.blockedOn(b);
}
});
復(fù)制代碼 代碼如下:
sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){
public sun.reflect.ConstantPool getConstantPool(Class klass) {
return klass.getConstantPool();
}
public void setAnnotationType(Class klass, AnnotationType type) {
klass.setAnnotationType(type);
}
public AnnotationType getAnnotationType(Class klass) {
return klass.getAnnotationType();
}
public <E extends Enum<E>>
E[] getEnumConstantsShared(Class<E> klass) {
return klass.getEnumConstantsShared();
}
public void blockedOn(Thread t, Interruptible b) {
t.blockedOn(b);
}
});
2. Thread.interrupt()
復(fù)制代碼 代碼如下:
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(); //回調(diào)鉤子
return;
}
}
interrupt0();
}
復(fù)制代碼 代碼如下:
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(); //回調(diào)鉤子
return;
}
}
interrupt0();
}
更多
更多關(guān)于Thread.stop,suspend,resume,interrupt的使用注意點(diǎn),可以看一下sun的文檔,比如http://download.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
最后來解答一下之前的幾個(gè)問題:
問題1: Thread.interrupt()方法和InterruptedException異常的關(guān)系?是由interrupt觸發(fā)產(chǎn)生了InterruptedException異常?
答: Thread.interrupt()只是在Object.wait() .Object.join(), Object.sleep()幾個(gè)方法會(huì)主動(dòng)拋出InterruptedException異常。而在其他的的block常見,只是通過設(shè)置了Thread的一個(gè)標(biāo)志位信息,需要程序自我進(jìn)行處理。
復(fù)制代碼 代碼如下:
if (Thread.interrupted()) // Clears interrupted status!
throw new InterruptedException();
復(fù)制代碼 代碼如下:
if (Thread.interrupted()) // Clears interrupted status!
throw new InterruptedException();
問題2:Thread.interrupt()會(huì)中斷線程什么狀態(tài)的工作? RUNNING or BLOCKING?
答:Thread.interrupt設(shè)計(jì)的目的主要是用于處理線程處于block狀態(tài),比如wait(),sleep()狀態(tài)就是個(gè)例子。但可以在程序設(shè)計(jì)時(shí)為支持task cancel,同樣可以支持RUNNING狀態(tài)。比如Object.join()和一些支持interrupt的一些nio channel設(shè)計(jì)。
問題3: 一般Thread編程需要關(guān)注interrupt中斷不?一般怎么處理?可以用來做什么?
答: interrupt用途: unBlock操作,支持任務(wù)cancel, 數(shù)據(jù)清理等。
問題4: LockSupport.park()和unpark(),與object.wait()和notify()的區(qū)別?
答:
1. 面向的主體不一樣。LockSuport主要是針對(duì)Thread進(jìn)進(jìn)行阻塞處理,可以指定阻塞隊(duì)列的目標(biāo)對(duì)象,每次可以指定具體的線程喚醒。Object.wait()是以對(duì)象為緯度,阻塞當(dāng)前的線程和喚醒單個(gè)(隨機(jī))或者所有線程。
2. 實(shí)現(xiàn)機(jī)制不同。雖然LockSuport可以指定monitor的object對(duì)象,但和object.wait(),兩者的阻塞隊(duì)列并不交叉。可以看下測(cè)試?yán)?。object.notifyAll()不能喚醒LockSupport的阻塞Thread.
問題5: LockSupport.park(Object blocker)傳遞的blocker對(duì)象做什么用?
答: 對(duì)應(yīng)的blcoker會(huì)記錄在Thread的一個(gè)parkBlocker屬性中,通過jstack命令可以非常方便的監(jiān)控具體的阻塞對(duì)象.
復(fù)制代碼 代碼如下:
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker); // 設(shè)置Thread.parkBlocker屬性的值
unsafe.park(false, 0L);
setBlocker(t, null); // 清除Thread.parkBlocker屬性的值
}
復(fù)制代碼 代碼如下:
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker); // 設(shè)置Thread.parkBlocker屬性的值
unsafe.park(false, 0L);
setBlocker(t, null); // 清除Thread.parkBlocker屬性的值
}
具體LockSupport的javadoc描述也比較清楚,可以看下:

問題6: LockSupport能響應(yīng)Thread.interrupt()事件不?會(huì)拋出InterruptedException異常?
答:能響應(yīng)interrupt事件,但不會(huì)拋出InterruptedException異常。針對(duì)LockSupport對(duì)Thread.interrupte支持,也先看一下javadoc中的描述:

相關(guān)測(cè)試代碼
復(fù)制代碼 代碼如下:
package com.agapple.cocurrent;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
public class LockSupportTest {
private static LockSupportTest blocker = new LockSupportTest();
public static void main(String args[]) throws Exception {
lockSupportTest();
parkTest();
interruptParkTest();
interruptSleepTest();
interruptWaitTest();
}
/**
* LockSupport.park對(duì)象后,嘗試獲取Thread.blocker對(duì)象,調(diào)用其single喚醒
*
* @throws Exception
*/
private static void lockSupportTest() throws Exception {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() throws Exception {
// 嘗試sleep 5s
System.out.println("blocker");
LockSupport.park(blocker);
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "lockSupportTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(150);
synchronized (blocker) {
Field field = Thread.class.getDeclaredField("parkBlocker");
field.setAccessible(true);
Object fBlocker = field.get(t);
System.out.println(blocker == fBlocker);
Thread.sleep(100);
System.out.println("notifyAll");
blocker.notifyAll();
}
}
/**
* 嘗試去中斷一個(gè)object.wait(),會(huì)拋出對(duì)應(yīng)的InterruptedException異常
*
* @throws InterruptedException
*/
private static void interruptWaitTest() throws InterruptedException {
final Object obj = new Object();
Thread t = doTest(new TestCallBack() {
@Override
public void callback() throws Exception {
// 嘗試sleep 5s
obj.wait();
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "interruptWaitTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
t.interrupt(); // 檢查下在park時(shí),是否響應(yīng)中斷
}
/**
* 嘗試去中斷一個(gè)Thread.sleep(),會(huì)拋出對(duì)應(yīng)的InterruptedException異常
*
* @throws InterruptedException
*/
private static void interruptSleepTest() throws InterruptedException {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() throws Exception {
// 嘗試sleep 5s
Thread.sleep(5000);
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "interruptSleepTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
t.interrupt(); // 檢查下在park時(shí),是否響應(yīng)中斷
}
/**
* 嘗試去中斷一個(gè)LockSupport.park(),會(huì)有響應(yīng)但不會(huì)拋出InterruptedException異常
*
* @throws InterruptedException
*/
private static void interruptParkTest() throws InterruptedException {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() {
// 嘗試去park 自己線程
LockSupport.parkNanos(blocker, TimeUnit.SECONDS.toNanos(5));
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "interruptParkTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
t.interrupt(); // 檢查下在park時(shí),是否響應(yīng)中斷
}
/**
* 嘗試去中斷一個(gè)LockSupport.unPark(),會(huì)有響應(yīng)
*
* @throws InterruptedException
*/
private static void parkTest() throws InterruptedException {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() {
// 嘗試去park 自己線程
LockSupport.park(blocker);
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "parkTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
LockSupport.unpark(t);
t.interrupt();
}
public static Thread doTest(final TestCallBack call) {
return new Thread() {
@Override
public void run() {
File file = new File("/dev/urandom"); // 讀取linux黑洞
try {
FileInputStream in = new FileInputStream(file);
byte[] bytes = new byte[1024];
while (in.read(bytes, 0, 1024) > 0) {
if (Thread.interrupted()) {
throw new InterruptedException("");
}
System.out.println(bytes[0]);
Thread.sleep(100);
long start = System.currentTimeMillis();
call.callback();
System.out.println(call.getName() + " callback finish cost : "
+ (System.currentTimeMillis() - start));
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
}
}
interface TestCallBack {
public void callback() throws Exception;
public String getName();
}
復(fù)制代碼 代碼如下:
package com.agapple.cocurrent;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
public class LockSupportTest {
private static LockSupportTest blocker = new LockSupportTest();
public static void main(String args[]) throws Exception {
lockSupportTest();
parkTest();
interruptParkTest();
interruptSleepTest();
interruptWaitTest();
}
/**
* LockSupport.park對(duì)象后,嘗試獲取Thread.blocker對(duì)象,調(diào)用其single喚醒
*
* @throws Exception
*/
private static void lockSupportTest() throws Exception {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() throws Exception {
// 嘗試sleep 5s
System.out.println("blocker");
LockSupport.park(blocker);
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "lockSupportTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(150);
synchronized (blocker) {
Field field = Thread.class.getDeclaredField("parkBlocker");
field.setAccessible(true);
Object fBlocker = field.get(t);
System.out.println(blocker == fBlocker);
Thread.sleep(100);
System.out.println("notifyAll");
blocker.notifyAll();
}
}
/**
* 嘗試去中斷一個(gè)object.wait(),會(huì)拋出對(duì)應(yīng)的InterruptedException異常
*
* @throws InterruptedException
*/
private static void interruptWaitTest() throws InterruptedException {
final Object obj = new Object();
Thread t = doTest(new TestCallBack() {
@Override
public void callback() throws Exception {
// 嘗試sleep 5s
obj.wait();
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "interruptWaitTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
t.interrupt(); // 檢查下在park時(shí),是否響應(yīng)中斷
}
/**
* 嘗試去中斷一個(gè)Thread.sleep(),會(huì)拋出對(duì)應(yīng)的InterruptedException異常
*
* @throws InterruptedException
*/
private static void interruptSleepTest() throws InterruptedException {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() throws Exception {
// 嘗試sleep 5s
Thread.sleep(5000);
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "interruptSleepTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
t.interrupt(); // 檢查下在park時(shí),是否響應(yīng)中斷
}
/**
* 嘗試去中斷一個(gè)LockSupport.park(),會(huì)有響應(yīng)但不會(huì)拋出InterruptedException異常
*
* @throws InterruptedException
*/
private static void interruptParkTest() throws InterruptedException {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() {
// 嘗試去park 自己線程
LockSupport.parkNanos(blocker, TimeUnit.SECONDS.toNanos(5));
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "interruptParkTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
t.interrupt(); // 檢查下在park時(shí),是否響應(yīng)中斷
}
/**
* 嘗試去中斷一個(gè)LockSupport.unPark(),會(huì)有響應(yīng)
*
* @throws InterruptedException
*/
private static void parkTest() throws InterruptedException {
Thread t = doTest(new TestCallBack() {
@Override
public void callback() {
// 嘗試去park 自己線程
LockSupport.park(blocker);
System.out.println("wakeup now!");
}
@Override
public String getName() {
return "parkTest";
}
});
t.start(); // 啟動(dòng)讀取線程
Thread.sleep(2000);
LockSupport.unpark(t);
t.interrupt();
}
public static Thread doTest(final TestCallBack call) {
return new Thread() {
@Override
public void run() {
File file = new File("/dev/urandom"); // 讀取linux黑洞
try {
FileInputStream in = new FileInputStream(file);
byte[] bytes = new byte[1024];
while (in.read(bytes, 0, 1024) > 0) {
if (Thread.interrupted()) {
throw new InterruptedException("");
}
System.out.println(bytes[0]);
Thread.sleep(100);
long start = System.currentTimeMillis();
call.callback();
System.out.println(call.getName() + " callback finish cost : "
+ (System.currentTimeMillis() - start));
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
}
}
interface TestCallBack {
public void callback() throws Exception;
public String getName();
}
最后
發(fā)覺文章越寫越長(zhǎng),那就索性發(fā)到了論壇,大家一起討論下.畢竟文章中描述的都是一些使用層面的東東,并沒有從操作系統(tǒng)或者sun native實(shí)現(xiàn)上去介紹Thread的一些機(jī)制,熟悉這塊的大牛門也可以出來發(fā)表下高見.
相關(guān)文章
基于IOC容器實(shí)現(xiàn)管理mybatis過程解析
這篇文章主要介紹了基于IOC容器實(shí)現(xiàn)管理mybatis過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07Intellj Idea中的maven工程Java文件顏色不對(duì),未被識(shí)別的解決
這篇文章主要介紹了Intellj Idea中的maven工程Java文件顏色不對(duì),未被識(shí)別的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08Spring整合mybatis、springMVC總結(jié)
這篇文章主要為大家詳細(xì)介紹了Java整合Mybatis,SpringMVC,文中有詳細(xì)的代碼示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2023-05-05Spring Boot集群管理工具KafkaAdminClient使用方法解析
這篇文章主要介紹了Spring Boot集群管理工具KafkaAdminClient使用方法解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02java實(shí)現(xiàn)數(shù)據(jù)庫主鍵生成示例
這篇文章主要介紹了java實(shí)現(xiàn)數(shù)據(jù)庫主鍵生成示例,需要的朋友可以參考下2014-03-03Java連接操作Oracle數(shù)據(jù)庫代碼詳解
這篇文章主要介紹了Java連接操作Oracle數(shù)據(jù)庫代碼詳解的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06Java找不到或無法加載主類及編碼錯(cuò)誤問題的解決方案
今天小編就為大家分享一篇關(guān)于Java找不到或無法加載主類及編碼錯(cuò)誤問題的解決方案,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-02-02