多线程学习笔记——安全退出线程

1.stop()方法退出线程

线程退出有多种方法,我们先来演示线程.stop()方法,此方法用于强制结束一个线程

threadObj.stop();

我们现在来看一下示例代码:

public class ThreadTest {
    
    
    public static void main(String[] args)  {
    
    
        Thread thread = new Thread( () -> {
    
    
            int i = 0,j=0;

            try {
    
    
                while(true) {
    
    
                    i++;
                    System.err.println("i:"+i);
                    Thread.sleep(100);
                    j++;
                    System.err.println("j:"+j);
                }
            }catch(Exception ex)
            {
    
    
                ex.printStackTrace();
            }
        });
        thread.start();
        try {
    
    
            Thread.sleep(1000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        thread.stop();
    }
}

在这里插入图片描述

上面方法分别使变量i和变量j分别间隔100毫秒后自增,并且输出对应的值,可以看到,现成正常退出!

在这里插入图片描述

但是我们翻看代码可以发现,stop()方法已经被标为过时,并不推荐使用,因为stop()方法是强制退出线程,并不保证所有必要逻辑执行完全,容易出现不可预料的错误:在这里插入图片描述上方图片可以看到,i++后,j并未自增,而此时线程已经停止,这如果是在业务代码中,就容易导致不可预料的后果!

2.interrupt()方法标记退出线程

既然强制退出线程容易导致安全问题,那么我们就需要另一种新的方法,在需要线程需要退出时加上标记,然后用自己的逻辑手动的退出线程。

threadObj.interrupt();//将当前线程标记为退出状态
Thread.currentThread().isInterrupted()//判断当前线程是否已在停止状态

注意:调用此方法后并不会立即停止线程,此方法只是将此线程标记为退出状态,需要配合手动判断退出线程!

public class ThreadTest {
    
    
    public static void main(String[] args)  {
    
    
        Thread thread = new Thread( () -> {
    
    
            int i = 0,j=0;
            try {
    
    
                while(true) {
    
    
                    i++;
                    System.err.println("i:"+i);
                    j++;
                    System.err.println("j:"+j);
                    if(Thread.currentThread().isInterrupted())
                    {
    
    
                        System.err.println("自定义退出逻辑");
                        break;
                    }
                }
            }catch(Exception ex)
            {
    
    
                ex.printStackTrace();
            }
        });
        thread.start();
        try {
    
    
            Thread.sleep(1000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        thread.interrupt();
    }
}

在这里插入图片描述
可以看到,这里就可以在所有业务执行完后安全的退出线程。

3.如何处理java.lang.InterruptedException

在这里插入图片描述
如果我们在上方代码中,添加了Thread.sleep()方法,就会发现如下异常:
在这里插入图片描述

这是因为线程在休眠时,被设置为中断状态,所以触发了此异常,并且将线程中断状态设置为False。所以一定要在此处加上异常处理逻辑,确保线程安全退出。

		while (true) {
    
    
                i++;
                System.err.println("i:" + i);
                try {
    
    
                    Thread.sleep(100);
                } catch (Exception ex) {
    
    
                    ex.printStackTrace();
                }
                j++;
                System.err.println("j:" + j);
                System.err.println(Thread.currentThread().isInterrupted());
            }

在这里插入图片描述

这就导致线程可以正常执行,并且之后的isInterrupted()退出线程方法不生效。

那么如何正确的面对此异常呢?

  • 在Catch中直接退出线程
 while (true) {
    
    
     i++;
     System.err.println("i:" + i);
     try {
    
    
        Thread.sleep(100);
     } catch (Exception ex) {
    
    
         break;
     }
     j++;
     System.err.println("j:" + j);
     System.err.println(Thread.currentThread().isInterrupted());
 }
  • 在Catch中将中断状态重新置位true
    注意:此时线程并未停止,仍需手动退出线程
while (true) {
    
    
   i++;
   System.err.println("i:" + i);
   try {
    
    
       Thread.sleep(100);
   } catch (Exception ex) {
    
    
       Thread.currentThread().interrupt();
   }
      j++;
   System.err.println("j:" + j);
   if(Thread.currentThread().isInterrupted())
   {
    
    
          break;
   }
}
  • 捕获后不处理(极度不推荐)
    如果此时捕获后不做任何处理的话,因为异常之后,此线程的中断状态会被重新置为false,所以并不会被下方的isInterrupted()方法捕获并退出,所以不推荐使用。
while (true) {
    
    
   i++;
   System.err.println("i:" + i);
   try {
    
    
       Thread.sleep(100);
   } catch (Exception ex) {
    
    

   }
      j++;
   System.err.println("j:" + j);
   if(Thread.currentThread().isInterrupted())
   {
    
    
          break;
   }
}

总的来说,如果可以避免,不使用线程休眠的方法,如果使用,则需要在保证逻辑安全的前提下使用,并正确的处理异常,退出线程!

猜你喜欢

转载自blog.csdn.net/qq_42628989/article/details/107215382