java什么线程不可被中断,Java如何中断一个正在运行的线程
大家好,关于java什么线程不可被中断很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于Java如何中断一个正在运行的线程的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!
Java如何中断一个正在运行的线程
程序是很简易的然而在编程人员面前多线程呈现出了一组新的难题如果没有被恰当的解决将导致意外的行为以及细微的难以发现的错误
在本篇文章中我们针对这些难题之一如何中断一个正在运行的线程
背景中断(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描述了这一方式
ListingBclassExample extendsThread{volatilebooleanstop=false;publicstaticvoidmain(Stringargs[])throwsException{Example thread=newExample();System out println( Startingthread);thread start();Thread sleep();System out println( Askingthreadtostop);thread stop=true;Thread sleep();System out println( Stoppingapplication);//System exit();}publicvoidrun(){while(!stop){System out println( Threadisrunning);longtime=System currentTimeMillis();while((System currentTimeMillis() time<)&&(!stop)){}}System out println( Threadexitingunderrequest);}}
运行Listing B中的代码将产生如下输出(注意线程是如何有秩序的退出的)
Startingthread Threadisrunning Threadisrunning Threadisrunning Askingthreadtostop Threadexitingunderrequest Stoppingapplication
虽然该方法要求一些编码但并不难实现同时它给予线程机会进行必要的清理工作这在任何一个多线程应用程序中都是绝对需要的请确认将共享变量定义成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这个示例描述了该技术
ListingCclassExample extendsThread{volatilebooleanstop=false;publicstaticvoidmain(Stringargs[])throwsException{Example thread=newExample();System out println( Startingthread);thread start();Thread sleep();System out println( Askingthreadtostop);thread stop=true;//如果线程阻塞将不会检查此变量thread interrupt();Thread sleep();System out println( Stoppingapplication);//System exit();}publicvoidrun(){while(!stop){System out println( Threadrunning);try{Thread sleep();}catch(InterruptedExceptione){System out println( Threadinterrupted);}}System out println( Threadexitingunderrequest);}}
一旦Listing C中的Thread interrupt()被调用线程便收到一个异常于是逃离了阻塞状态并确定应该停止运行以上代码将得到下面的输出
Startingthread Threadrunning Threadrunning Threadrunning Askingthreadtostop Threadinterrupted Threadexitingunderrequest Stoppingapplication
中断I/O操作
然而如果线程在I/O操作进行时被阻塞又会如何?I/O操作可以阻塞线程一段相当长的时间特别是牵扯到网络应用时例如服务器可能需要等待一个请求(request)又或者一个网络应用程序可能要等待远端主机的响应
如果你正使用通道(channels)(这是在Java中引入的新的I/O API)那么被阻塞的线程将收到一个 ClosedByInterruptException异常如果情况是这样其代码的逻辑和第三个例子中的是一样的只是异常不同而已
但是你可能正使用Java之前就存在的传统的I/O而且要求更多的工作既然这样 Thread interrupt()将不起作用因为线程将不会退出被阻塞状态 Listing D描述了这一行为尽管interrupt()被调用线程也不会退出被阻塞状态
ListingDimportjava io*;classExample extendsThread{publicstaticvoidmain(Stringargs[])throwsException{Example thread=newExample();System out println( Startingthread);thread start();Thread sleep();System out println( Interruptingthread);thread interrupt();Thread sleep();System out println( Stoppingapplication);//System exit();}publicvoidrun(){ServerSocketsocket;try{socket=newServerSocket();}catch(IOExceptione){System out println( Couldnotcreatethesocket);return;}while(true){System out println( Waitingforconnection);try{Socketsock=socket accept();}catch(IOExceptione){System out println( accept()failedorinterrupted);}}}}
很幸运 Java平台为这种情形提供了一项解决方案即调用阻塞该线程的套接字的close()方法在这种情形下如果线程被I/O操作阻塞该线程将接收到一个SocketException异常这与使用interrupt()方法引起一个InterruptedException异常被抛出非常相似
唯一要说明的是必须存在socket的引用(reference)只有这样close()方法才能被调用这意味着socket对象必须被共享 Listing E描述了这一情形运行逻辑和以前的示例是相同的
ListingEimport*;importjava io*;classExample extendsThread{volatilebooleanstop=false;volatileServerSocketsocket;publicstaticvoidmain(Stringargs[])throwsException{Example thread=newExample();System out println( Startingthread);thread start();Thread sleep();System out println( Askingthreadtostop);thread stop=true;thread socket close();Thread sleep();System out println( Stoppingapplication);//System exit();}publicvoidrun(){try{socket=newServerSocket();}catch(IOExceptione){System out println( Couldnotcreatethesocket);return;}while(!stop){System out println( Waitingforconnection);try{Socketsock=socket accept();}catch(IOExceptione){System out println( accept()failedorinterrupted);}}System out println( Threadexitingunderrequest);}}
以下是运行Listing E中代码后的输出
Startingthread Waitingforconnection Askingthreadtostop accept()failedorinterrupted Threadexitingunderrequest Stoppingapplication
多线程是一个强大的工具然而它正呈现出一系列难题其中之一是如何中断一个正在运行的线程如果恰当地实现使用上述技术中断线程将比使用Java平台上已经提供的内嵌操作更为简单 lishixinzhi/Article/program/Java/gj/201311/27481Java多线程之阻塞I/O如何中断
阻塞的I/O线程在关闭线程时并不会被打断,需要关闭资源才能打断。
1.执行socketInput.close();阻塞可中断。
2.执行System.in.close();阻塞没有中断。
复制代码
package Thread.Interrupting;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class CloseResource{
public static void main(String[] args) throws Exception{
//堵塞的I/O线程不会被打断,需要关闭资源才能打断
ExecutorService exec= Executors.newCachedThreadPool();
ServerSocket server= new ServerSocket(8080);
InputStream socketInput= new Socket("localhost", 8080)
.getInputStream();
exec.execute(new IOBlocked(socketInput));
exec.execute(new IOBlocked(System.in));
TimeUnit.MILLISECONDS.sleep(100);
System.out.println("Shutting down all threads");
exec.shutdownNow();
TimeUnit.SECONDS.sleep(1);
System.out.println("Closing"+ socketInput.getClass().getName());
socketInput.close();
TimeUnit.SECONDS.sleep(1);
System.out.println("Close"+ System.in.getClass().getName());
System.in.close();
}
}
复制代码
被阻塞的nio通道在关闭线程后会自动响应中断阻塞,不需要关闭底层资源。
复制代码
package Thread.Interrupting;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
class NIOBlocked implements Runnable{
private final SocketChannel sc;
public NIOBlocked(SocketChannel sc){
this.sc= sc;
}
@Override
public void run(){
try{
System.out.println("Waiting for read() in"+ this);
sc.read(ByteBuffer.allocate(1));
} catch(ClosedByInterruptException e){
System.out.println("ClosedByInterruptException");
} catch(AsynchronousCloseException e){
System.out.println("AsynchronousCloseException");
} catch(IOException e){
throw new RuntimeException(e);
}
System.out.println("Exiting NIOBlocked.run()"+ this);
}
}
public class NIOInterruption{
public static void main(String[] args) throws Exception{
//被阻塞的nio通道会自动地响应中断
ExecutorService exec= Executors.newCachedThreadPool();
ServerSocket server= new ServerSocket(8080);
InetSocketAddress isa= new InetSocketAddress("localhost", 8080);
SocketChannel sc1= SocketChannel.open(isa);
SocketChannel sc2= SocketChannel.open(isa);
Future<?> f= exec.submit(new NIOBlocked(sc1));
exec.execute(new NIOBlocked(sc2));
exec.shutdown();
TimeUnit.SECONDS.sleep(1);
f.cancel(true);
TimeUnit.SECONDS.sleep(1);
sc2.close();
}
}
JavaThread线程的状态有哪些
[1]新生状态(New):当一个线程的实例被创建即使用new关键字和Thread类或其子类创建一个线程对象后,此时该线程处于新生(new)状态,处于新生状态的线程有自己的内存空间,但该线程并没有运行,此时线程还不是活着的(notalive)。
[2]就绪状态(Runnable):通过调用线程实例的start()方法来启动线程使线程进入就绪状态(runnable);处于就绪状态的线程已经具备了运行条件,但还没有被分配到CPU即不一定会被立即执行,此时处于线程就绪队列,等待系统为其分配CPCU,等待状态并不是执行状态;此时线程是活着的(alive)。
[3]运行状态(Running):一旦获取CPU(被JVM选中),线程就进入运行(running)状态,线程的run()方法才开始被执行;在运行状态的线程执行自己的run()方法中的操作,直到调用其他的方法而终止、或者等待某种资源而阻塞、或者完成任务而死亡;如果在给定的时间片内没有执行结束,就会被系统给换下来回到线程的等待状态;此时线程是活着的(alive)。
[4]阻塞状态(Blocked):通过调用join()、sleep()、wait()或者资源被暂用使线程处于阻塞(blocked)状态;处于Blocking状态的线程仍然是活着的(alive)。
[5]死亡状态(Dead):当一个线程的run()方法运行完毕或被中断或被异常退出,该线程到达死亡(dead)状态。此时可能仍然存在一个该Thread的实例对象,当该Thread已经不可能在被作为一个可被独立执行的线程对待了,线程的独立的callstack已经被dissolved。一旦某一线程进入Dead状态,他就再也不能进入一个独立线程的生命周期了。对于一个处于Dead状态的线程调用start()方法,会出现一个运行期(runtimeexception)的异常;处于Dead状态的线程不是活着的(notalive)。
文章到此结束,如果本次分享的java什么线程不可被中断和Java如何中断一个正在运行的线程的问题解决了您的问题,那么我们由衷的感到高兴!