线程终止常用的四种方式:
终止线程的第一种方式:等待run()或者是call()方法执行完毕
终止线程的第二种方式:设置共享变量,如boolean flag。flag作为线程是否继续执行的标志
终止线程的第三种方式:利用Thread类提供的interrupt()和InterruptedException。
终止线程的第四种方式:利用Thread类提供的interrupt()和isInterrupted()。
考虑下面这段程序:
public class MyThread {
public static void main(String[] args) throws InterruptedException {
Thread thread = new ThreadImpl();
thread.start();
}
}
class ThreadImpl extends Thread {
private static double value = 0;
int i = 0, j = 0;
@Override
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + " 执行之前, value = " + value);
while (i++ < Integer.MAX_VALUE)
while (j++ < Integer.MAX_VALUE)
value += 0.1;
System.out.println("线程 " + Thread.currentThread().getName() + " 执行之后, value = " + value);
}
}
线程的核心任务是value自增0.1,但是有两层循环。
终止线程的第一种方式:等待run()或者是call()方法执行完毕,线程自然就结束了(这里run()执行时间太长,不能忍)。
但是很多时候,需要在线程执行过程中终止线程,老版JDK的Thread类提供stop()方法,JDK1.8以后已经被标记为depecated,仍然可以终止线程(已测试),但不建议使用,具体原因网上很多。知道是已废弃的就别用了。。。
终止线程的第二种方式:设置共享变量,如boolean flag。
flag作为线程是否继续执行的标志,属于线程所有。根据需要可以设定为static变量或者实例变量,最好用volatile关键字修饰,这样可以保证flag在线程间的可见性。
如下代码,当flag为true时,线程执行,当需要终止线程时,只需要将该线程对象的flag = false;
public class MyThread {
public static void main(String[] args) throws InterruptedException {
ThreadImpl thread = new ThreadImpl();
thread.start();
//do something
thread.flag = false;
}
}
class ThreadImpl extends Thread {
private static double value = 0;
public volatile boolean flag = true;//也可以定义为private,然后利用setter进行赋值
int i = 0, j = 0;
@Override
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + " 执行之前, value = " + value);
while (i++ < Integer.MAX_VALUE && flag)
while (j++ < Integer.MAX_VALUE && flag)
value += 0.1;
System.out.println("线程 " + Thread.currentThread().getName() + " 执行之后, value = " + value);
}
}
终止线程的第三种方式:利用Thread类提供的interrupt()和InterruptedException。
需要注意的是,thread.interrupt()只是会设置thread的interrupt flag,而不会正真的终止线程,因此在thread.interrupt()后,可以利用wait、sleep、join等操作收到interrupt()时会抛出InterruptedException异常的特性来终止线程,try … catch…
try{
//do something
}catch(InterruptedException e){
//do something after interruption
}
示例代码如下:
public class MyThread {
public static void main(String[] args) {
ThreadImpl thread = new ThreadImpl();
thread.start();
thread.interrupt();
if (thread.isInterrupted())
System.out.println("线程被中断");
}
}
class ThreadImpl extends Thread {
public static double value = 0;
int i = 0, j = 0;
@Override
public void run() {
try {
System.out.println("线程 " + Thread.currentThread().getName() + " 执行之前, value = " + value);
while (i++ < Integer.MAX_VALUE) {
value += 0.1;
Thread.sleep(1000);
}
System.out.println("线程 " + Thread.currentThread().getName() + " 执行之后, value = " + value);
} catch (InterruptedException e) {
System.out.println("发生中断时, value = " + value);
e.printStackTrace();
}
}
}
输出如下:
线程被中断
线程 Thread-0 执行之前, value = 0.0
发生中断时, value = 0.1
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at threadPool.ThreadImpl.run(MyThread.java:25)
终止线程的第四种方式:利用Thread类提供的interrupt()和isInterrupted()。
public class MyThread {
public static void main(String[] args) {
ThreadImpl thread = new ThreadImpl();
thread.start();
thread.interrupt();
}
}
class ThreadImpl extends Thread {
public static double value = 0;
int i = 0;
@Override
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + " 执行之前, value = " + value);
while (i++ < Integer.MAX_VALUE) {
value += 0.1;
}
System.out.println("线程 " + Thread.currentThread().getName() + " 执行之后, value = " + value);
if (this.isInterrupted()) {
System.out.println("线程被中断");
return;
}
}
}
输出如下
线程 Thread-0 执行之前, value = 0.0
线程 Thread-0 执行之后, value = 2.1474835660588232E8
线程被中断
以上四种方式中,需要根据实际情况来决定采用何种方式终止线程。
1. 如果线程中存在循环,可用共享变量的方式;
2. 如果需要线程发生终端时返回一些属性,那么建议采用interrupt()+isInterrupted()的方式;
3. 如果线程中存在sleep\wait\join或者其他io操作,则可采用interrupt()+捕获InterruptedException的方式;
补充:关于interrupt
一下是JDK1.8中关于interrupt的实现与说明。
简单的说:
1. 当thread被wait(),sleep(),join()阻塞时,线程状态被清理,同时会收到InterruptedException;
2. 当thread被io,nio阻塞时,也会收到异常;
3. 当1,2都没发生时,thread的 interrupt status被set。
/**
* Interrupts this thread.
*
* Unless the current thread is interrupting itself, which is
* always permitted, the {@link #checkAccess() checkAccess} method
* of this thread is invoked, which may cause a {@link
* SecurityException} to be thrown.
*
*
If this thread is blocked in an invocation of the {@link
* Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
* Object#wait(long, int) wait(long, int)} methods of the {@link Object}
* class, or of the {@link #join()}, {@link #join(long)}, {@link
* #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
* methods of this class, then its interrupt status will be cleared and it
* will receive an {@link InterruptedException}.
*
*
If this thread is blocked in an I/O operation upon an {@link
* java.nio.channels.InterruptibleChannel InterruptibleChannel}
* then the channel will be closed, the thread's interrupt
* status will be set, and the thread will receive a {@link
* java.nio.channels.ClosedByInterruptException}.
*
* If this thread is blocked in a {@link java.nio.channels.Selector}
* then the thread'
s interrupt status will be set and it will return
* immediately from the selection operation, possibly with a non-zero
* value, just as if the selector's {@link
* java.nio.channels.Selector#wakeup wakeup} method were invoked.
*
* If none of the previous conditions hold then this thread'
s interrupt
* status will be set.
*
* Interrupting a thread that is not alive need not have any effect.
*
* @throws SecurityException
* if the current thread cannot modify this thread
*
* @revised 6.0
* @spec JSR-51
*/
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(this);
return;
}
}
interrupt0();
}