您的位置:首页 > 编程语言 > Java开发

Java终止线程的四种方法

2017-10-05 19:24 232 查看
线程终止常用的四种方式:

终止线程的第一种方式:等待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(
4000
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.
*
* <p> 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.
*
* <p> 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}.
*
* <p> 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}.
*
* <p> 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.
*
* <p> If none of the previous conditions hold then this thread's interrupt
* status will be set. </p>
*
* <p> 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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: