Open funnycoding opened 4 years ago
线程可能会阻塞或暂停执行,原因有多种:
当线程阻塞时,它通常被「挂起」,并处于某种『阻塞状态』**(BLOCK、WAITING 或 TIMED_WAITING)。阻塞操作与执行时间很长的普通操作的差别在于 : 被阻塞的线程必须等待某个 不受它控制 的事件发生后 才能继续执行,例如「等待 I/O 操作完成」,「等待某个锁可用」,或者「等待外部计算的结束」。
当某个外部事件发生时,线程被置回 RUNABLE 可运行状态,并可以再次被调度执行。
BlockingQueue 的 put 和 take 等方法会抛出 受检查异常(Checked Exception) InterruptedException,这与类库中其他一些方法的做法相同,例如 Thread.sleep。
BlockingQueue
put
take
InterruptedException
Thread.sleep
当某方法抛出 InterruptedException 时,表示该方法是一个阻塞方法,如果这个方法被中断,那么它将努力提前结束 「阻塞状态」。<---【阻塞方法的定义,比如 Thread.slee】
Thread.slee
Thread 提供了 interrupt 方法,用于中断线程或者查询线程是否已经被中断。 每个线程都有一个布尔类型的属性,表示线程的中断状态,当中断线程时,将设置这个状态。
Thread
interrupt
中断是一种「协作机制」,一个线程不能强制其他线程停止正在执行的操作而去执行其他的操作。<---【也就是只能建议,而不能强制停止】
当 「线程A」 中断 「线程B」 时,A 仅仅是要求 B 在执行到某个可以暂停的地方停止正在执行的操作 —— 前提是 「线程B」 愿意停止下。虽然在 API 或者 语言规范中并没有为中断定义任何特定应用级别的语义,但最常使用中断的情况就是 「取消某个操作」。
方法对中断请求的响应度越高,就越容易及时取消那些执行时间很长的操作。<---【那么方法的响应度是可以设置的吗? 总是把话说一半。。。】
当在代码中调用了一个将抛出 InterruptedException 异常的方法时,你自己的方法也就变成了一个阻塞方法,并且必须要处理对中断的响应,对于库代码来说,有两种基本选择:
Runnable
程序清单 5-10 恢复中断状态以屏蔽中断:
// Restoring the interrupted status so as not to swallow the interrupt // 恢复中断状态以避免中断被屏蔽 public class TaskRunnable implements Runnable { BlockingQueue<Task> queue; @Override public void run() { try { processTask(queue.take()); } catch (InterruptedException e) { // 恢复被中断的状态 将调用者线程的中断状态设为true。 Thread.currentThread().interrupt(); } } // 对Task进行处理的业务逻辑代码 void processTask(Task task) { // 处理 task } interface Task { } }
还可以采用一些更复杂的终端处理方法,但是上述两种方法已经可以应付大多数情况了。 然而在出现 InterruptedException 时不应该做的事情是:捕获它但是不做出任何响应。【也就是异常的侵吞,这种操作在任何时候应该都是不推荐的】。这将使调用栈更上层的代码无法对中断采取处理措施,因为线程被中断的证据已经丢失。
只有在一种特殊的情况下才能屏蔽中断 —— 对 Thread 进行扩展,并且能够调用栈上更高层的代码。 [第7章]() 将进一步介绍 「取消」 和 「中断」 等操作。
5.4 阻塞方法与中断方法
线程可能会阻塞或暂停执行,原因有多种:
当线程阻塞时,它通常被「挂起」,并处于某种『阻塞状态』**(BLOCK、WAITING 或 TIMED_WAITING)。阻塞操作与执行时间很长的普通操作的差别在于 : 被阻塞的线程必须等待某个 不受它控制 的事件发生后 才能继续执行,例如「等待 I/O 操作完成」,「等待某个锁可用」,或者「等待外部计算的结束」。
当某个外部事件发生时,线程被置回 RUNABLE 可运行状态,并可以再次被调度执行。
BlockingQueue
的put
和take
等方法会抛出 受检查异常(Checked Exception)InterruptedException
,这与类库中其他一些方法的做法相同,例如Thread.sleep
。当某方法抛出
InterruptedException
时,表示该方法是一个阻塞方法,如果这个方法被中断,那么它将努力提前结束 「阻塞状态」。<---【阻塞方法的定义,比如Thread.slee
】Thread
提供了interrupt
方法,用于中断线程或者查询线程是否已经被中断。 每个线程都有一个布尔类型的属性,表示线程的中断状态,当中断线程时,将设置这个状态。中断是一种「协作机制」,一个线程不能强制其他线程停止正在执行的操作而去执行其他的操作。<---【也就是只能建议,而不能强制停止】
当 「线程A」 中断 「线程B」 时,A 仅仅是要求 B 在执行到某个可以暂停的地方停止正在执行的操作 —— 前提是 「线程B」 愿意停止下。虽然在 API 或者 语言规范中并没有为中断定义任何特定应用级别的语义,但最常使用中断的情况就是 「取消某个操作」。
方法对中断请求的响应度越高,就越容易及时取消那些执行时间很长的操作。<---【那么方法的响应度是可以设置的吗? 总是把话说一半。。。】
当在代码中调用了一个将抛出 InterruptedException 异常的方法时,你自己的方法也就变成了一个阻塞方法,并且必须要处理对中断的响应,对于库代码来说,有两种基本选择:
InterruptedException
。避开这个异常通常是最明智的策略 —— 只需要把 InterruptedException 抛出给方法的调用者。InterruptedException
时,例如 当代码是Runnable
的一部分时,这种情况下必须捕获InterruptedException
,并通过调用当前线程上的interrupt
方法恢复中断状态,这样在调用栈中的更高层代码将看到引发了一个中断: 如程序清单 5-10还可以采用一些更复杂的终端处理方法,但是上述两种方法已经可以应付大多数情况了。 然而在出现
InterruptedException
时不应该做的事情是:捕获它但是不做出任何响应。【也就是异常的侵吞,这种操作在任何时候应该都是不推荐的】。这将使调用栈更上层的代码无法对中断采取处理措施,因为线程被中断的证据已经丢失。只有在一种特殊的情况下才能屏蔽中断 —— 对 Thread 进行扩展,并且能够调用栈上更高层的代码。 [第7章]() 将进一步介绍 「取消」 和 「中断」 等操作。
脑图