如何中断“同步/阻塞”线程,not only interrupt()
如何中断一个正在执行的线程?
线程中断,意味着该线程在完成任务之前停止其正在进行的一切,有效地中止其当前的操作。
那么,线程接下为是死亡、还是等待新的任务,或是继续运行至下一步。
【方法一】使用共享变量Shared Variable
1. 需要线程“周期性”的核查这一变量,然后有秩序的中止任务。
2. 将共享变量定义成“volatile”型,或将它的一切方法封入“synchronized”块或方法中。
3. 局限性:如果线程被阻塞,便不能核查共享变量,该方法将失效。例如,Object.wait(), ServerSocket.accept()和DatagramSocket.receive(),等等。
public class Main extends Thread {
volatile boolean stop = false;
public static void main(String[] args) {
Main thread = new Main();
try {
System.out.println("starting thread");
thread.start();
Thread.sleep(3000);
System.out.println("asking thread to stop");
thread.stop = true;
Thread.sleep(3000);
System.out.println("stopping application");
} catch (InterruptedException e) {
System.out.println("sleep interrupted");
;
}
}
public void run() {
while (!stop) { // 周期性的检查
System.out.println("running");
long time = System.currentTimeMillis();
while (System.currentTimeMillis() - time < 1000) {
;
}
}
System.out.println("thread exiting under request..");
}
}
【方法二】对于阻塞情况,使用Thread.interrupt()
(1)interrupt(),不会中断一个正在运行的线程,它实际完成的是,在线程“受到阻塞时”抛出一个中断信号,这样线程就得以退出阻塞状态。更确定的说,如果线程被Object.wait(), Thread.join()和Thread.sleep()三种方法之一阻塞,那么,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。
(2)局限性:interrupt(),可以很好的解救阻塞中的线程,但如果一直占用着CPU就仍然中断不了.
public class Main extends Thread {
boolean stop = false;
public static void main(String[] args) {
Main thread = new Main();
try {
System.out.println("starting thread");
thread.start();
Thread.sleep(3000);
System.out.println("asking thread to stop");
thread.stop = true; // 如果线程阻塞,将不会检查此变量
thread.interrupt(); // 中断
Thread.sleep(3000);
System.out.println("stopping application");
} catch (InterruptedException e) {
System.out.println("sleep interrupted");
;
}
}
public void run() {
while (!stop) {
System.out.println("running");
try{
Thread.sleep(1000);
}catch(InterruptedException e){
System.out.println("Thread interrupted");
}
}
System.out.println("thread exiting under request..");
}
}
【方法三】“野蛮”行径,未尝不可
(1)对于同步情况,可以开“捣乱”线程,强抛RuntimeException
例如,同步等待在主线程A中做,那么:
a) 在A中中开线程B,做的事情:sleep(timeout)时间,醒了就抛出RuntimeException;
b) 在A中做一些事情,同步神马的亦可;
c) timeout时间到,若2)仍未结束,RuntimeException也会使其结束的;
(2)劣势:这种方法,强抛runtimeException出来,无法catch,自然也就意味着不能做任何处理,眼睁睁的看着它抛。
Semaphore s = new Semaphore(0);
TimeoutThread t = new TimeoutThread(5000L, new TimeoutException("超时"));
try {
t.start();
// 同步等待代码
System.out.println("try to acquire");
s.acquire();
System.out.println("acquired");
t.cancel();
}catch (InterruptedException e) {
System.out.println("interrupt exception");
}
【方法四】……
【备注】:
(1)不推荐使用:Thread.stop()
(2)这样使用interrupt,并不能真正中断线程,所以不要被名字蒙蔽了:
public class Main extends Thread {
volatile boolean stop = false;
public static void main(String[] args) {
Main thread = new Main();
try {
System.out.println("starting thread");
thread.start();
Thread.sleep(3000);
System.out.println("Interrupting thread");
thread.interrupt(); // 线程并没有真正被中断,只是置了中断位
Thread.sleep(3000);
System.out.println("stopping application");
} catch (InterruptedException e) {
System.out.println("sleep interrupted");
;
}
}
public void run() {
while (!stop) {
System.out.println("running");
long time = System.currentTimeMillis();// 这样的操作,一直占用着CPU,非"阻塞",所以interrupt()对其无用,不生效.
while (System.currentTimeMillis() - time < 1000) {
;
}
}
System.out.println("thread exiting under request..");
}
}