这是一个来自 Java 编程思想的例子,它只是想表达 sleep 的线程可中断,但同步 IO 等待资源,或同步获得锁失败的线程,是不可同步的。
//: concurrency/Interrupting.java
// Interrupting a blocked thread.
import java.util.concurrent.*;
import java.io.*;
import static net.mindview.util.Print.*;
class SleepBlocked implements Runnable {
public void run() {
try {
TimeUnit.SECONDS.sleep(100);
} catch(InterruptedException e) {
print("InterruptedException");
}
print("Exiting SleepBlocked.run()");
}
}
class IOBlocked implements Runnable {
private InputStream in;
public IOBlocked(InputStream is) { in = is; }
public void run() {
try {
print("Waiting for read():");
in.read();
} catch(IOException e) {
if(Thread.currentThread().isInterrupted()) {
print("Interrupted from blocked I/O");
} else {
throw new RuntimeException(e);
}
}
print("Exiting IOBlocked.run()");
}
}
class SynchronizedBlocked implements Runnable {
public synchronized void f() {
while(true) // Never releases lock
Thread.yield();
}
public SynchronizedBlocked() {
new Thread() {
public void run() {
f(); // Lock acquired by this thread
}
}.start();
}
public void run() {
print("Trying to call f()");
f();
print("Exiting SynchronizedBlocked.run()");
}
}
public class Interrupting {
private static ExecutorService exec =
Executors.newCachedThreadPool();
static void test(Runnable r) throws InterruptedException{
Future<?> f = exec.submit(r);
TimeUnit.MILLISECONDS.sleep(100);
print("Interrupting " + r.getClass().getName());
f.cancel(true); // Interrupts if running
print("Interrupt sent to " + r.getClass().getName());
}
public static void main(String[] args) throws Exception {
test(new SleepBlocked());
test(new IOBlocked(System.in));
test(new SynchronizedBlocked());
test(new Runnable() { //自己写的测试线程
@Override
public void run () {
System.out.println("1 start run");
try {
new Object().wait(); //这句不抛异常,为什么?
} catch (InterruptedException e) {
System.out.println("1 catch InterruptedException");
e.printStackTrace();
}
System.out.println("1 exit run");
}
});
TimeUnit.SECONDS.sleep(3);
print("Aborting with System.exit(0)");
new Object().wait(); //这句抛异常
System.exit(0); // ... since last 2 interrupts failed
}
}
打印结果:
Interrupting SleepBlocked
Interrupt sent to SleepBlocked
InterruptedException
Exiting SleepBlocked.run()
Waiting for read():
Interrupting IOBlocked
Interrupt sent to IOBlocked
Trying to call f()
Interrupting SynchronizedBlocked
Interrupt sent to SynchronizedBlocked
1 start run
Interrupting Interrupting$1
Interrupt sent to Interrupting$1 //而且看起来,中断也没起作用?(如果有作用,之后应该出现这个线程的打印结果)
Aborting with System.exit(0)
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at Interrupting.main(Interrupting.java:92)
我知道 wait 正确用法是在同步方法或同步块中使用, 所以现在问题有 2 个,
test(new Runnable() {
@Override
public void run () {
synchronized(this) {
System.out.println("1 start run");
try {
wait();
} catch (InterruptedException e) {
System.out.println("1 catch InterruptedException");
e.printStackTrace();
}
System.out.println("1 exit run");
}
}
});
然后我试了上面这个版本的,打印结果如下:
Interrupting SleepBlocked
Interrupt sent to SleepBlocked
InterruptedException
Exiting SleepBlocked.run()
Waiting for read():
Interrupting IOBlocked
Interrupt sent to IOBlocked
Trying to call f()
Interrupting SynchronizedBlocked
Interrupt sent to SynchronizedBlocked
1 start run
Interrupting Interrupting$1
Interrupt sent to Interrupting$1
1 catch InterruptedException
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at Interrupting$1.run(Interrupting.java:75)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
1 exit run
Aborting with System.exit(0)
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at Interrupting.main(Interrupting.java:86)
所以,wait 之前是获得锁的情况,才可以被中断呗?
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.