Java之正确的停止线程

作者: mixiu | 来源:发表于2016-10-25 13:26 被阅读718次

    API提供的方法存在的问题

    public class StopThread3 {
        private static Object lock = new Object();
        private static int number = 0;
        static int tmp = 0;
        public static void main(String[] args) {
            ThreadOne t1 = new ThreadOne();
            t1.start();
            ThreadTwo t2 = new ThreadTwo();
            t2.start();
            t1.stop();
            t2.stop();
        }
    
        static class ThreadOne extends Thread {
    
            public void run() {
                add();
            }
            private void add() {
    
                while (true) {
                    synchronized (lock) {
                        System.out.println("number=" + number);
                        tmp++;
                        number++;
                    }
                }
            }
        }
    
        static class ThreadTwo extends Thread {
    
            public void run() {
                add();
            }
            private void add() {
                while (true) {
                    synchronized (lock) {
                        System.out.println("number=" + number);
                        tmp++;
                        number++;
                    }
                }
            }
    
        }
    
    }
    

    其中的一次输出:
    number=347
    number=348
    number=348
    number=349
    number=350

    替代stop的方法

    class MyThread extends Thread {
         volatile boolean flag = false;
         public void stopThread(){
             flag = true;
         }
         @Override
         public void run() {
             while (flag) {                
                 process();
             }
         }
         private void process() {
             ...
         }
     }
    

    volatile

    flag必须使用volatile修饰,或者访问flag的方法是同步的,如下:

    class MyThread extends Thread {
        boolean flag = false;  
        public synchronized void stopThread(){
            flag = true;
        }
        @Override
        public void run() {  
            while (flag) {                
                process();
            }
    
        }
        private void process() {
            ...
        }
    }
    

    这个是很常用的方法但是在某些情况下并不适用。
    在上面的荔枝中如果process()是一个很耗时的操作,当在别的线程中修改了flag并不能停止线程。这时需要用到Thread.interrupt

    使用 Thread.interrupt

    class MyThread extends Thread {
            public void stopThread() {
                interrupt();
            }
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    process();
                }
                System.out.println("...end...");
            }
            private void process() {
                System.out.println("---process---");
                try {
                    Thread.sleep(1000 * 1000);
                } catch (InterruptedException ex) {
                    System.out.println("InterruptedException");
                }
            }
      }
    

    Thread.interrupt只能中断响应InterruptedException的线程。如果将上例中的process()改为下面的形式,将不能终止线程的执行。

    private void process() {
      System.out.println("---process---");
      while (true) {}
    }
    

    Override interrupt()

    对于不能响应InterruptedException的情况可以针对具体的情况,重写interrupt()方法。如果我们试图读取一个已经关闭的InputStream时,会产生一个stream is closed的错误,当我们在interrupt方法中关闭了InputStream,读取这个InputStream的线程就会中断。记住:使用此方法不能在catch进行可以中终止线程的操作,如printStackTrace()

    public class StopThread2 {
    
        public static void main(String[] args) {
            new StopThread2().test();
        }
    
        private void test() {
            final MyThread myThread = new MyThread();
            myThread.start();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1200);
                    } catch (InterruptedException ex) {
                    }
                    myThread.stopThread();
    
                }
            }).start();
    
        }
    
        class MyThread extends Thread {
    
            private URLConnection conn;
            private volatile InputStream in;
    
            public void stopThread() {
                interrupt();
            }
    
            @Override
            public void interrupt() {
                try {
                    in.close();
                } catch (IOException ex) {
                    System.out.println("IOException:" + ex.getMessage());
                }
                super.interrupt();
            }
    
            @Override
            public void run() {
                try {
                    URL url = new URL("http://new.hellopojo.site/AndroidDev");
    
                    conn = url.openConnection();
                    in = conn.getInputStream();
    
                    process(in);
    
                    System.out.println("...end...");
                } catch (Exception ex) {
                    System.out.println("---" + ex.getStackTrace());
                }
            }
    
            private void process(InputStream in) {
                try {
                    System.out.println("---process---");
                    InputStreamReader isr = new InputStreamReader(in, "utf-8");
                    BufferedReader reader = new BufferedReader(isr);
                    String line = null;
                    while ((line = reader.readLine()) != null) {
                        System.out.println("" + line);
                    }
                } catch (IOException ex) {
                    System.out.println("IOException:" + ex.getMessage());
                }
            }
        }
    }
    

    相关文章

      网友评论

        本文标题:Java之正确的停止线程

        本文链接:https://www.haomeiwen.com/subject/mhuruttx.html