1 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
2 使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。
3 使用interrupt方法中断线程。
1 使用退出标志终止线程
当run方法执行完后,线程就会退出。但有时run方法是永远不会结束的。如在服务端程序中使用线程进行监听客户端请求,或是其他的需要循环处理的任务。在这种情况下,一般是将这些任务放在一个循环中,如while循环。如果想让循环永远运行下去,可以使用while(true){……}来处理。但要想使while循环在某一特定条件下退出,最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出。下面给出了一个利用退出标志终止线程的例子。
package chapter2;
public class ThreadFlag extends Thread
{
public volatile boolean exit = false;
public void run()
{
while (!exit);
}
public static void main(String[] args) throws Exception
{
ThreadFlag thread = new ThreadFlag();
threadstart();
sleep(5000); // 主线程延迟5秒
threadexit = true; // 终止线程thread
threadjoin();
Systemoutprintln("线程退出!");
}
}
在上面代码中定义了一个退出标志exit,当exit为true时,while循环退出,exit的默认值为false在定义exit时,使用了一个Java关键字volatile,这个关键字的目的是使exit同步,也就是说在同一时刻只能由一个线程来修改exit的值,
2 使用stop方法终止线程
使用stop方法可以强行终止正在运行或挂起的线程。我们可以使用如下的代码来终止线程:
threadstop();
虽然使用上面的代码可以终止线程,但使用stop方法是很危险的,就象突然关闭计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果,因此,并不推荐使用stop方法来终止线程。
3 使用interrupt方法终止线程
使用interrupt方法来终端线程可分为两种情况:
(1)线程处于阻塞状态,如使用了sleep方法。
(2)使用while(!isInterrupted()){……}来判断线程是否被中断。
在第一种情况下使用interrupt方法,sleep方法将抛出一个InterruptedException例外,而在第二种情况下线程将直接退出。下面的代码演示了在第一种情况下使用interrupt方法。
package chapter2;
public class ThreadInterrupt extends Thread
{
public void run()
{
try
{
sleep(50000); // 延迟50秒
}
catch (InterruptedException e)
{
Systemoutprintln(egetMessage());
}
}
public static void main(String[] args) throws Exception
{
Thread thread = new ThreadInterrupt();
threadstart();
Systemoutprintln("在50秒之内按任意键中断线程!");
Systeminread();
threadinterrupt();
threadjoin();
Systemoutprintln("线程已经退出!");
}
}
上面代码的运行结果如下:
在50秒之内按任意键中断线程!
sleep interrupted
线程已经退出!
在调用interrupt方法后, sleep方法抛出异常,然后输出错误信息:sleep interrupted
注意:在Thread类中有两个方法可以判断线程是否通过interrupt方法被终止。一个是静态的方法interrupted(),一个是非静态的方法isInterrupted(),这两个方法的区别是interrupted用来判断当前线是否被中断,而isInterrupted可以用来判断其他线程是否被中断。因此,while (!isInterrupted())也可以换成while (!Threadinterrupted())。thread可以用destroy方法销毁,但它不保证资源被释放,所以只能用在无资源的情况下。一般都自行控制代码逻辑让run()方法正常执行完,常用的方法包括可以被打断(在代码里检测interrupted())、检测状态标识退出循环等。JDK中提供了stop方法,但是现在已经不建议使用了。这个方法会使线程突然停止,没有经过别的处理,所以在有的时候会造成脏读。在一些情况下,需要采取其他方式来停止线程。
例:
public class test {
public static void main(String[] args) throws InterruptedException {
try{
Thread thread1=new Thread(new TheThread(),"thread1");
thread1start();
Threadsleep(2000);
thread1interrupt();//采用异常停止线程
}catch (InterruptedException e){
eprintStackTrace();
}
}
}
class TheThread extends Thread{
public void run() {
superrun();
for (int i = 0; i < 10; i++) {
if(thisinterrupted()){
break;
}
Systemoutprintln(ThreadcurrentThread()getName() + ":" + i);
}
}
}你2个button中 监听的 线程 不是一个线程 ,当然停止不了。我帮你改下 如下:
import javaawtEventQueue;
import javaawteventActionEvent;
import javaawteventActionListener;
import javaxswingJButton;
import javaxswingJFrame;
import javaxswingJLabel;
import javaxswingJPanel;
import javaxswingUIManager;
import javaxswingborderEmptyBorder;
public class DynamicTextLabel extends JFrame{
//声明一个线程 Thread 为了2个button监听获得同一个线程
private Thread t;
private static final long serialVersionUID = -2035256617544621708L; private JPanel contentPane;
private JLabel label;
private JButton btnNewButton_1;
public static void main(String[] args) {
try {
UIManagersetLookAndFeel("comsunjavaswingplafnimbusNimbusLookAndFeel");
} catch (Throwable e) {
eprintStackTrace();
}
EventQueueinvokeLater(new Runnable() {
public void run() {
try {
DynamicTextLabel frame = new DynamicTextLabel();
framesetVisible(true);
} catch (Exception e) {
eprintStackTrace();
} }
});
}
public DynamicTextLabel() {
setTitle("文字的跑马灯效果");
setDefaultCloseOperation(JFrameEXIT_ON_CLOSE);
setBounds(100, 100, 400, 149);
contentPane = new JPanel();
contentPanesetBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPanesetLayout(null);
label = new JLabel("明日科技");
labelsetBounds(10, 10, 48, 15);
contentPaneadd(label);
JButton btnNewButton = new JButton("||");
btnNewButtonaddActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//停止前面new的线程,对象的引用相同
if(t!=null){
tstop();
}
}
});
btnNewButtonsetBounds(59, 64, 93, 23);
contentPaneadd(btnNewButton);
btnNewButton_1 = new JButton("\u2192");
btnNewButton_1addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//产生一个线程
t= new Thread(new DynamicThread());
tstart();
}
});
btnNewButton_1setBounds(183, 64, 93, 23);
contentPaneadd(btnNewButton_1);}
private class DynamicThread implements Runnable {
@Override public void run() {
while (true) {
for (int i = 0; i < 400; i++) {
try {
Threadsleep(10);
} catch (InterruptedException e) {
eprintStackTrace();
}
labelsetLocation(i, 5);
}
}
}
}}
程序是很简易的 然而 在编程人员面前 多线程呈现出了一组新的难题 如果没有被恰当的解决 将导致意外的行为以及细微的 难以发现的错误
在本篇文章中 我们针对这些难题之一 如何中断一个正在运行的线程
背景中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切 有效地中止其当前的 *** 作 线程是死亡 还是等待新的任务或是继续运行至下一步 就取决于这个程序 虽然初次看来它可能显得简单 但是 你必须进行一些预警以实现期望的结果 你最好还是牢记以下的几点告诫
首先 忘掉Thread stop方法 虽然它确实停止了一个正在运行的线程 然而 这种方法是不安全也是不受提倡的 这意味着 在未来的JAVA版本中 它将不复存在
一些轻率的家伙可能被另一种方法Thread interrupt所迷惑 尽管 其名称似乎在暗示著什么 然而 这种方法并不会中断一个正在运行的线程(待会将进一步说明) 正如Listing A中描述的那样 它创建了一个线程 并且试图使用Thread interrupt方法停止该线程 Thread sleep()方法的调用 为线程的初始化和中止提供了充裕的时间 线程本身并不参与任何有用的 *** 作
class Example extends Thread { boolean stop=false; public static void main( String args[] ) throws Exception { Example thread = new Example (); System out println( Starting thread ); thread start(); Thread sleep( ); System out println( Interrupting thread ); thread interrupt(); Thread sleep( ); System out println( Stopping application ); //System exit( ); } public void run() { while(!stop){ System out println( Thread is running ); long time = System currentTimeMillis(); while((System currentTimeMillis() time < )) { } } System out println( Thread exiting under request ); } }
如果你运行了Listing A中的代码 你将在控制台看到以下输出
Starting thread Thread is running Thread is running Thread is running Interrupting thread Thread is running Thread is running Thread is running Stopping application Thread is running Thread is running Thread is running
甚至 在Thread interrupt()被调用后 线程仍然继续运行
真正地中断一个线程
中断线程最好的 最受推荐的方式是 使用共享变量(shared variable)发出信号 告诉线程必须停止正在运行的任务 线程必须周期性的核查这一变量(尤其在冗余 *** 作期间) 然后有秩序地中止任务 Listing B描述了这一方式
Listing Bclass Example extends Thread { volatile boolean stop = false; public static void main( String args[] ) throws Exception { Example thread = new Example (); System out println( Starting thread ); thread start(); Thread sleep( ); System out println( Asking thread to stop ); thread stop = true; Thread sleep( ); System out println( Stopping application ); //System exit( ); } public void run() { while ( !stop ) { System out println( Thread is running ); long time = System currentTimeMillis(); while ( (System currentTimeMillis() time < ) && (!stop) ) { } } System out println( Thread exiting under request ); }}
运行Listing B中的代码将产生如下输出(注意线程是如何有秩序的退出的)
Starting thread Thread is running Thread is running Thread is running Asking thread to stop Thread exiting under request Stopping application
虽然该方法要求一些编码 但并不难实现 同时 它给予线程机会进行必要的清理工作 这在任何一个多线程应用程序中都是绝对需要的 请确认将共享变量定义成volatile 类型或将对它的一切访问封入同步的块/方法(synchronized blocks/methods)中
到目前为止一切顺利!但是 当线程等待某些事件发生而被阻塞 又会发生什么?当然 如果线程被阻塞 它便不能核查共享变量 也就不能停止 这在许多情况下会发生 例如调用Object wait() ServerSocket accept()和DatagramSocket receive()时 这里仅举出一些
他们都可能永久的阻塞线程 即使发生超时 在超时期满之前持续等待也是不可行和不适当的 所以 要使用某种机制使得线程更早地退出被阻塞的状态
很不幸运 不存在这样一种机制对所有的情况都适用 但是 根据情况不同却可以使用特定的技术 在下面的环节 我将解答一下最普遍的例子
使用Thread interrupt()中断线程
正如Listing A中所描述的 Thread interrupt()方法不会中断一个正在运行的线程 这一方法实际上完成的是 在线程受到阻塞时抛出一个中断信号 这样线程就得以退出阻塞的状态 更确切的说 如果线程被Object wait Thread join和 Thread sleep三种方法之一阻塞 那么 它将接收到一个中断异常(InterruptedException) 从而提早地终结被阻塞状态
因此 如果线程被上述几种方法阻塞 正确的停止线程方式是设置共享变量 并调用interrupt()(注意变量应该先设置) 如果线程没有被阻塞 这时调用interrupt()将不起作用 否则 线程就将得到异常(该线程必须事先预备好处理此状况) 接着逃离阻塞状态 在任何一种情况中 最后线程都将检查共享变量然后再停止 Listing C这个示例描述了该技术
Listing Cclass Example extends Thread { volatile boolean stop = false; public static void main( String args[] ) throws Exception { Example thread = new Example (); System out println( Starting thread ); thread start(); Thread sleep( ); System out println( Asking thread to stop ); thread stop = true;//如果线程阻塞 将不会检查此变量 thread interrupt(); Thread sleep( ); System out println( Stopping application ); //System exit( ); } public void run() { while ( !stop ) { System out println( Thread running ); try { Thread sleep( ); } catch ( InterruptedException e ) { System out println( Thread interrupted ); } } System out println( Thread exiting under request ); }}
一旦Listing C中的Thread interrupt()被调用 线程便收到一个异常 于是逃离了阻塞状态并确定应该停止 运行以上代码将得到下面的输出
Starting thread Thread running Thread running Thread running Asking thread to stop Thread interrupted Thread exiting under request Stopping application
中断I/O *** 作
然而 如果线程在I/O *** 作进行时被阻塞 又会如何?I/O *** 作可以阻塞线程一段相当长的时间 特别是牵扯到网络应用时 例如 服务器可能需要等待一个请求(request) 又或者 一个网络应用程序可能要等待远端主机的响应
如果你正使用通道(channels)(这是在Java 中引入的新的I/O API) 那么被阻塞的线程将收到一个 ClosedByInterruptException异常 如果情况是这样 其代码的逻辑和第三个例子中的是一样的 只是异常不同而已
但是 你可能正使用Java 之前就存在的传统的I/O 而且要求更多的工作 既然这样 Thread interrupt()将不起作用 因为线程将不会退出被阻塞状态 Listing D描述了这一行为 尽管interrupt()被调用 线程也不会退出被阻塞状态
Listing Dimport java io ;class Example extends Thread { public static void main( String args[] ) throws Exception { Example thread = new Example (); System out println( Starting thread ); thread start(); Thread sleep( ); System out println( Interrupting thread ); thread interrupt(); Thread sleep( ); System out println( Stopping application ); //System exit( ); } public void run() { ServerSocket socket; try { socket = new ServerSocket( ); } catch ( IOException e ) { System out println( Could not create the socket ); return; } while ( true ) { System out println( Waiting for connection ); try { Socket sock = socket accept(); } catch ( IOException e ) { System out println( accept() failed or interrupted ); } } }}
很幸运 Java平台为这种情形提供了一项解决方案 即调用阻塞该线程的套接字的close()方法 在这种情形下 如果线程被I/O *** 作阻塞 该线程将接收到一个SocketException异常 这与使用interrupt()方法引起一个InterruptedException异常被抛出非常相似
唯一要说明的是 必须存在socket的引用(reference) 只有这样close()方法才能被调用 这意味着socket对象必须被共享 Listing E描述了这一情形 运行逻辑和以前的示例是相同的
Listing Eimport ;import java io ;class Example extends Thread { volatile boolean stop = false; volatile ServerSocket socket; public static void main( String args[] ) throws Exception { Example thread = new Example (); System out println( Starting thread ); thread start(); Thread sleep( ); System out println( Asking thread to stop ); thread stop = true; thread socket close(); Thread sleep( ); System out println( Stopping application ); //System exit( ); } public void run() { try { socket = new ServerSocket( ); } catch ( IOException e ) { System out println( Could not create the socket ); return; } while ( !stop ) { System out println( Waiting for connection ); try { Socket sock = socket accept(); } catch ( IOException e ) { System out println( accept() failed or interrupted ); } } System out println( Thread exiting under request ); }}
以下是运行Listing E中代码后的输出
Starting thread Waiting for connection Asking thread to stop accept() failed or interrupted Thread exiting under request Stopping application
多线程是一个强大的工具 然而它正呈现出一系列难题 其中之一是如何中断一个正在运行的线程 如果恰当地实现 使用上述技术中断线程将比使用Java平台上已经提供的内嵌 *** 作更为简单 lishixinzhi/Article/program/Java/gj/201311/27481
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)