`

Thread详解一(interrupt)

阅读更多
 

Thread详解一(interrupt)

分类: 读书笔记之java 1515人阅读 评论(0) 收藏 举报

1,在定义Thread的时候选择实现Runnable接口比继承Thead更灵活,因为java是单继承的嘛。

2,setPriority()方法改变其优先权。

3,setDaemon()方法讲线程设置为后台线程。该方法需要在start()方法之前调用。

4,线程的状态(Thread.State,可以通过getState方法获得):

1)、新状态:线程对象已经创建,还没有在其上调用start()方法。 
2)、可运行状态:当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞 、等待或睡眠状态回来后,也返回到可运行状态。 
3)、运行状态:线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。 
4)、等待/阻塞/睡眠状态:这是线程有资格运行时它所处的状态。实际上这个三状态组合为一种,其共同点是:线程仍旧是活的,但是当前没有条件运行。换句话说,它是可运 行的,但是如果某件事件出现,他可能返回到可运行状态
。 
5)、死亡态:当线程的run()方法完成时就认为它死去。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦死亡,就不能复生。 如果在一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。

 

5,线程进入阻塞状态原因

1),调用sleep()方法

2),调用wait()使线程挂起。知道线程得到了notify()或notifyAll()消息,线程才会进入可运行状态。

3),线程在等待某个输入/输出完成。

4),线程视图在某个对象上调用其同步控制方法,但对象锁不可用。

 

6,sleep方法,sleep时间没有被确保说一定是精确的,这个受限于操作系统的策略。另外,在sleep阶段内线程可以被终止by interrupts。无论如何,你都不能假定触发sleep会让线程很精确的暂停预设的时间。

 

7,http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html

interrupt对于一个线程,标示着它应该停下它正在做的事情来做些其他的。具体的是由程序员来决定一个线程如何回应interrupt,一般都是让这个线程终止。
一个线程通过调用 interrupt()方法来触发这个线程的interrupt事件。为了正确的实现interrupt机制,被中断的线程需要支持自己的interruption。

 

当外部线程对某线程调用了thread.interrupt()方法后,java语言的处理机制如下:
       如果该线程处在可中断状态下,(调用了xx.wait(),或者Selector.select(),Thread.sleep()等特定会发生阻塞的 api),那么该线程会立即被唤醒,同时会受到一个InterruptedException,同时,如果是阻塞在io上,对应的资源会被关闭。如果该线 程接下来不执行“Thread.interrupted()方法(不是interrupt),那么该线程处理任何io资源的时候,都会导致这些资源关闭。 当然,解决的办法就是调用一下interrupted(),不过这里需要程序员自行根据代码的逻辑来设定,根据自己的需求确认是否可以直接忽略该中断,还 是应该马上退出。

如果该线 程处在不可中断状态下,就是没有调用上述api,那么java只是设置一下该线程的interrupt状态,其他事情都不会发生,如果该线程之后会调用行 数阻塞API,那到时候线程会马会上跳出,并抛出InterruptedException,接下来的事情就跟第一种状况一致了。如果不会调用阻塞 API,那么这个线程就会一直执行下去。除非你就是要实现这样的线程,一般高性能的代码中肯定会有wait(),yield()之类出让cpu的函数,不 会发生后者的情况。


关于线程阻塞:
如果一个线程由于等待某些事件的发生而被阻塞,又该如何实现该线程的中断呢?比如当一个线程由于需要等候键盘输入而被阻塞,处于不可运行状态时,即使主程序中将该线程的共享变量设置为true,但该线程此时根本无法检查循环标志,当然也就无法立即中断。
其实,这种情况经常会发生,比如调用Thread.join()方法,或者Thread.sleep()方法,在网络中调用 ServerSocket.accept()方法,或者调用了DatagramSocket.receive()方法时,都有可能导致线程阻塞。即便这 样,仍然不要使用stop()方法,而是使用Thread提供的interrupt()方法,因为该方法虽然不会中断一个正在运行的线程,但是它可以使一 个被阻塞的线程抛出一个中断异常,从而使线程提前结束阻塞状态,退出堵塞代码。

 

interrupt机制实现是用了中间的标志位interrupt status。调用Thread.interrupt这个静态方法会检查状态并清空重置状态,而非静态方法isInterrupted只是进行状态的查询,无清空重置。即:

Thread.interrupted 是 currentThread.isInterrupted(true) , 会返回当前的interrupted状态位,并清空状态
thread.isInterrupted 是 isInterrupted(false) 只返回状态,不做清空处理

interrupt 方法并不直接中断线程或者抛出InterruptedException,而是设置 interrupted 标志位。Object.wait, Thread.sleep方法,会不断的轮询监听 interrupted 标志位,发现其设置为true后,会停止阻塞并抛出 InterruptedException异常。
Object.wait, Thread.join, Thread.sleep,  interrupt调用后,会清空其interrupt状态,并抛出InterruptedException异常

除以上清空外,其它阻塞,例如:IO操作的阻塞,java.nio.channels.InterruptibleChannel, channels.Selector, interrupt调用后,会设置其interrupt状态

假如在IO阻塞的interrupt调用后,不进行Thread.interrupted调用清除标志位,则下一次IO调用,会直接抛出异常。
nio.AbstractInterruptibleChannel通过实现Interruptible接口的对象,监听线程的interrupt事件,通过 sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), interruptibleObject); 注册监听器
在Channel每次做动作时,会通过Thread.currentThread().isInterrupted()检查线程的当前状态,假如正处于interrupted状态中,则调用interruptibleObject.interrupt方法

 

总结:程序应该对线程中断作出恰当的响应。响应方式通常有三种:(来自温绍锦(昵称:温少):http//www.cnblogs.com/jobs/)

 

至于具体让线程停止的方法,可以通过变量标志位,比如while(!stop){}配合上interrupt来实现,根据具体的需求,如果线程中未对interrupt状态做处理,直接调用interrupt方法想终止线程运行是行不通的。

 

8,join方法

join方法运行一个线程等待另外一个线程完成。如果t是一个线程对象,某个线程在另一个线程t上调用t.join(),此线程将被挂起,知道目标线程结束才恢复(即t.isAlive返回为false)。也可以在join()时带上个超时参数。join方法和sleep一样,都对被interrupt方法中断。

 

参考:http://daydayup1989.iteye.com/blog/785581

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics