另一个关于Thread的问题

xing19900712 2012-03-22 10:25:34
首先请各位放心,我会结贴的,发帖比较少,有两个(包括这个)正在解答的帖子没结,致使结贴率比较低(因为一共才发了5个帖子,算上这个)。(刚才有人说我结贴率低,不想回答我的问题)

java核心技术有一段这么说(别担心,后面我会翻译的):The isInterrupted check is neither necessary nor useful if you call the sleep method
(or another interruptible method) after every work iteration. If you call the sleep
method when the interrupted status is set, it doesn’t sleep. Instead, it clears the
status (!) and throws an InterruptedException. Therefore, if your loop calls sleep, don’t
check the interrupted status. Instead, catch the InterruptedException, like this:
public void run()
{
try
{
. . .
while (more work to do)
{
do more work
Thread.sleep(delay);
}
}
catch(InterruptedException e)
{
// thread was interrupted during sleep
}
finally
{
cleanup, if required
}
// exiting the run method terminates the thread
}


翻译过来大致就是,如果你在循环中调用thread的sleep()方法(或者其他可打断的方法),那么在循环头部利用isInterrupted()方法检测“打断位”是否被设置是没有必要而且没用的。因为如果打断位被设置了,sleep不会执行,它会清除打断位,并且抛出interruptedexception异常。所以,在循环中调用sleep的话,不要检测isInterrupted,而要捕获异常。

我想问,在循环中调用sleep(),循环就不能检测isInterrupted了吗?
我要是这样写:
while (!Thread.currentThread().isInterrupted() && more work to do)
如果打断位已经被设置,已经不会继续执行循环体了啊,而如果写成
while (more work to do)
是不会管打断位被没被设置,都会执行循环体。

另外,后者如果在打断位被设置的情况下,是以异常结束的,而前者直接跳过循环体,不抛出异常。
当让,如果循环头部检测时,打断位未被设置,而在循环体执行过程中被其他线程设置,二者是相同的。

写的比较凌乱,希望高手解答。
最后再次重申,我会结贴的!原因看开头!
谢谢!
...全文
207 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
wyx100 2012-03-30
  • 打赏
  • 举报
回复
就看LZ你怎么中断线程了,如果是调用interrupt中断,那么该方法的javadoc里已经清楚地说明了

rainsilence 2012-03-30
  • 打赏
  • 举报
回复
哎。。。

这段代码意思很明确了

while(more work to do){
try{
do more work
Thread.sleep(delay);
}catch(Exception e){
// thread was interrupted during sleep
}
}
如果打断位设为true,根本走不到while中的isInterrupted方法在sleep就直接停了。所以无所谓判断isInterrupted,因为false的时候永远循环,true的时候永远走不到。
qybao 2012-03-30
  • 打赏
  • 举报
回复
LS的都解释得很清楚了
注意循环结构的区别


//循环结构1 try在while的外层,书中的原文所指的是这样的结构
public void run()
{
try
{ //try在while外层,因为异常是在while的外层捕获的,
//所以发生异常时就会退出while层而跳转到catch部分
. . .
while (more work to do)
{
do more work
Thread.sleep(delay); //如果发生中断,将停止sleep,同时抛出中断异常
}
}
catch(InterruptedException e)
{
// thread was interrupted during sleep //所以就会退出while循环,跳转到这里
//所以while循环的条件里加上isInterrupted判断是没有意义的,因为已经退出while循环了
}
finally
{
cleanup, if required
}
// exiting the run method terminates the thread
}

//循环结构2 try在while的内层
public void run()
{
while (!isInterrupted() && more work to do)
{ //try在while的内层,因为异常是在while内层捕获的,
//所以发生异常的时候不会退出while,而是跳转到while内层的catch部分
try
{
do more work
Thread.sleep(delay); //如果发生中断,将停止sleep,同时抛出中断异常
}
catch(InterruptedException e)
{
// thread was interrupted during sleep
//所以这里将捕获中断异常,同时清空中断标志
//所以while的isInterrupted判断将变为false,
//也就是说该判断没有意义,画蛇添足,因为达不到中断后退出循环的效果
//要想达到中断退出循环的效果,就要自己在这里加上 break 来退出while循环
}
finally
{
cleanup, if required
}
// exiting the run method terminates the thread
}
}

xing19900712 2012-03-29
  • 打赏
  • 举报
回复
没人再回答下了吗?
xing19900712 2012-03-26
  • 打赏
  • 举报
回复
周末有事没上论坛,看到这么多回复,谢谢大家了。还有没有人能回答下?先顶,再慢慢看,谢谢各位!
rainsilence 2012-03-23
  • 打赏
  • 举报
回复
他的异常捕获在循环体的外面啊。

而且,他说的不要检测isInterrupted 是针对sleep,wait等打断方法所说的。因为很多人会因为会报异常而检测isInterrupted。这里说了如果需要打断,那么就直接异常终止操作就行。而不需要在循环条件中处理。
qybao 2012-03-22
  • 打赏
  • 举报
回复
就看LZ你怎么中断线程了,如果是调用interrupt中断,那么该方法的javadoc里已经清楚地说明了

interrupt
public void interrupt()中断线程。
如果当前线程没有中断它自己(这在任何情况下都是允许的),则该线程的 checkAccess 方法就会被调用,这可能抛出 SecurityException。

如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。

如果该线程在可中断的通道上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException。

如果该线程在一个 Selector 中受阻,则该线程的中断状态将被设置,它将立即从选择操作返回,并可能带有一个非零值,就好像调用了选择器的 wakeup 方法一样。

如果以前的条件都没有保存,则该线程的中断状态将被设置。

中断一个不处于活动状态的线程不需要任何作用。


抛出:
SecurityException - 如果当前线程无法修改该线程

红色部分,说明了LZ的问题,此时,中断状态被清空了,所以isInterrupted是返回false的
nmyangym 2012-03-22
  • 打赏
  • 举报
回复
nmyangym 2012-03-22
  • 打赏
  • 举报
回复
“我想问,在循环中调用sleep(),循环就不能检测isInterrupted了吗?”

这个也可以。但是要在捕获异常里面再次中断一次。(因为上一次的中断导致了两个结果:1 退出了sleep(),进入了异常处理程序。 2 把中断标志 isInterrupted 又清了(false).) 而这次中断,因为程序不在 sleep()里了,所以中断标志就维持true了,程序就可以检测到了。
xing19900712 2012-03-22
  • 打赏
  • 举报
回复
自己顶下吧。希望各位赐教!
冰思雨 2012-03-22
  • 打赏
  • 举报
回复
哦。楼主翻译的那个意思。
可以换一个角度来理解,就会明白了。

while(more work to do){
try{
do more work
Thread.sleep(delay);
}catch(Exception e){
// thread was interrupted during sleep
}
}


Try-Catch写在循环里面和外面是有区别的。

首先,看楼主的例子。
由于循环里面,能够抛出异常的,最明显的语句,就是Thread.sleep(delay);
当它抛出异常后,执行catch块和finnaly块的代码,
这时,循环已经退出了。那么,楼主所说的isInterrupted放在哪个前面,都没有什么意义,
当异常抛出后,不会再被调用。

再看,我写的这个样例。
由于Try-Catch写在里面,即使线程在sleep的时候被 interrupt 了,以为异常已经被捕获了,
那么,循环仍将继续。
这个时候,while条件换成楼主的 while (!Thread.currentThread().isInterrupted() && more work to do)
结果会比较纠结,大多数情况下和上面是一样的,偶尔会不同。
为什么呢 ?
首先,要想打断一个线程,先要设置打断位,这样,程序在执行到sleep的时候,自然会抛出异常。
其次,如果设置打断位的时候,线程正在sleep,那么执行打断处理。
第三,打断处理过程是,恢复打断位,抛出异常。
所以,一般情况下,循环仍在继续。
偶尔情况,是什么样的呢 ?
当程序执行到sleep之后,在while条件之前,这个时候进行打断操作,
这个时候,打断操作将打断位进行设置,之后,while条件变为false,循环退出,sleep不会被执行,
没有异常抛出。

我解释的够详细吗?
xing19900712 2012-03-22
  • 打赏
  • 举报
回复
看看还有没有其他解答。先顶上去,我慢慢看,谢谢各位

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧