什么是线程中断?在我们的Java程序中,执行线程其实不止一个。只有当所有的线程都执行完了,才认为Java程序执行完了。官方的话给大家描述一下:当所有的非daemon线程运行时,或者当其中一个线程调用System.exit()方法时,Java程序才能运行到结束。下面举例说明线程中断的应用场景。比如我们正在下载一部500多M的大电影。速度不是很快,几十KB就跑到这里来了,作为一个年轻人,等不及了,下不来了,所以我们此时的第一个操作就是结束下载文件的操作,这其实更接近于程序,比如这个时候我们需要中断这个线程。下面我们来写下载代码,看看如何中断一个线程。在这里我已经假设你已经掌握了如何创建线程。该程序模拟下载。一开始是获取系统时间,然后进入一个循环,每次获取系统时间,如果时间超过10秒,我们就中断线程,停止下载。下载速度为每秒1M:publicvoidrun(){intnumber=0;//记录程序的开始时间Longstart=System.currentTimeMillis();while(true){//每次执行的结束时间Longend=System.currentTimeMillis();//获取时间差Longinterval=end-start;//如果时间超过10秒,那么我们就结束下载if(interval>=10000){//中断线程interrupted();System.err.println("太慢了,下载不了");return;}elseif(number>=500){System.out.println("文件下载完成");//中断线程interrupted();return;}number++;System.out.println("Downloaded"+number+"M");try{Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}}}中断线程的方法Thread类为我们提供了中断线程的方法。我们先看看这个方法是如何中断线程的:publicstaticbooleaninterrupted(){returncurrentThread().isInterrupted(true);}这个方法是检查当前线程是否被中断,interrupt返回true,返回falseprivatenativebooleanisInterrupted(booleanClearInterrupted);通过查看源码我们可以发现,打断线程就是通过调用方法来判断线程是否被打断,并将值设置为true。这时候调用方法检查线程是否被中断,就会返回true。这里需要注意一个问题:Thread.interrupted()方法只是修改当前线程的状态,告诉他被中断了,但是对于非阻塞线程,它只是改变被中断的状态,即,Thread.isInterrupted()返回true,对于处于可取消阻塞状态的线程,比如等待这些函数的线程Thread.sleep(),在收到中断信号后会抛出InterruptedException,并将中断状态设置为true同时。线程休眠导致InterruptedException的原因,其实是有点学问的,写个错误的例子。我们来看一下,把这个问题彻底搞清楚:publicvoidrun(){intnumber=0;while(true){//检查线程是否中断,停止下载if(isInterrupted()){System.err.println("Too慢,下载不了");return;}elseif(number>=500){System.out.println("下载完成");return;}number++;System.out.println("已下载"+number+"M");try{Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}}}这是我们的主程序,等待10秒后中断线程publicstaticvoidmain(String[]args)throwsInterruptedException{Threadthread=newPrimeGenerator();//启动线程thread.start();//中断线程后waitingfor10secondsThread.sleep(1000);//中断线程thread.interrupt();}看起来很普通的程序,但事实并不是你看到的那样,其实这段代码会抛出InterruptedException,我们分析一下它的原因。这里我们首先要明白Thread.interrupt()方法不会中断一个正在运行的线程。当调用Thread.sleep()方法时,此时CPU将不再被占用。让我们分析一下我们的程序。我们要等待下载10秒,每次下载的速度是0.5M/S,也就是说当我们下载到5M的时候,等待的时间就到了。这个时候会调用Thread.interrupt()方法来中断线程,但是run()方法中的sleep还需要然后往下执行,不会因为中断而放弃执行后面的代码,那么在这个再次执行Thread.sleep()时,会抛出InterruptedException,因为当前线程已经被中断。说到这里,是不是已经明白这个异常的原因了?除此之外,还有另外两个原因导致线程产生InterruptedException。wait()和join()方法使用不当也会导致线程抛出异常。有两种方法可以检查线程是否被中断。在Thread类中,有一个方法interrupted()可以用来检查当前线程何时被中断,isInterrupted()方法可以用来检查当前线程是否被中断。事实上,中断线程的底层方法是将这个属性设置为true,而isInterrupted()方法只是返回这个属性的值。这两个方法的区别在于isInterrupted()不能改变interrupted()的属性值,而interrupted()方法可以改变interrupted的属性值,所以我们推荐在判断一个线程被中断时使用isInterrupted()。
