zoukankan      html  css  js  c++  java
  • Andorid 多线程(二):Thread 终止的方法

    Android 线程终止的方法

     前人:屌丝迷途          https://www.cnblogs.com/l2rf/p/5566895.html

               Marker_Sky      https://www.jianshu.com/p/49349eee9abc

    Thread.currentThread().getName()
    Thread.currentThread().getId()

    线程对象属于一次性消耗品,一般线程执行完run方法之后,线程就正常结束了,线程结束之后就报废了,不能再次start,只能新建一个线程对象。但有时run方法是永远不会结束的。例如在程序中使用线程进行Socket监听请求,或是其他的需要循环处理的任务。在这种情况下,一般是将这些任务放在一个循环中,如while循环。当需要结束线程时,如何退出线程呢?

    有三种方法可以结束线程:

    1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止

    2. 使用interrupt()方法中断线程

    3. 使用stop方法强行终止线程(不推荐使用,可能发生不可预料的结果)

    前两种方法都可以实现线程的正常退出,也就是要谈的优雅结束线程;第3种方法相当于电脑断电关机一样,是不安全的方法。

     

    1、使用退出标志终止线程

    使用一个变量来控制循环,例如最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出。代码如下:

     MainActivity.java

    package com.gatsby.threadsafe;
    
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        String TAG = "gatsby";
        Button btn1;
        static boolean isRunningCrush = false;
        ThreadSafe threadSafe = null;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Log.d(TAG, "The onCreate() event");
    
            btn1 = (Button) findViewById(R.id.btn1);
            btn1.setOnClickListener(this);
    
            threadSafe = new ThreadSafe(this);
            threadSafe.CrushThread();
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn1:
                    isRunningCrush = false;
                    break;
            }
        }
    
        /**
         * 当活动即将可见时调用
         */
        @Override
        protected void onStart() {
            super.onStart();
            Log.d(TAG, "The onStart() event");
        }
    
        /**
         * 当活动可见时调用
         */
        @Override
        protected void onResume() {
            super.onResume();
            Log.d(TAG, "The onResume() event");
            isRunningCrush = true;
        }
    
        /**
         * 当其他活动获得焦点时调用
         */
        @Override
        protected void onPause() {
            super.onPause();
            Log.d(TAG, "The onPause() event");
        }
    
        /**
         * 当活动不再可见时调用
         */
        @Override
        protected void onStop() {
            super.onStop();
            Log.d(TAG, "The onStop() event");
            isRunningCrush = false;
        }
    
        /**
         * 当活动将被销毁时调用
         */
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.d(TAG, "The onDestroy() event");
        }
    
    
    }

    ThreadSafe.java

    package com.gatsby.threadsafe;
    
    import android.content.Context;
    import android.util.Log;
    
    public class ThreadSafe {
    
        private Context mContext;
        private Thread mThread;
    
        public ThreadSafe(Context context) {
            super();
            this.mContext = mContext;
        }
    
        public void CrushThread() {
            MainActivity.isRunningCrush = true;
            if (mThread == null) {     //开启线程
                Log.d("gatsby","mThread == null");
                mThread = new Thread(new Crush());
                mThread.start();
            }
        }
    }
    
    class Crush implements Runnable {
    
        int i = 1;
        @Override
        public void run() {
            while (MainActivity.isRunningCrush) {
                Log.d("gatsby", "i->" + i++);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }

    定义了一个退出标志exit,当exit为true时,while循环退出,exit的默认值为false.在定义exit时,使用了一个Java关键字volatile,这个关键字的目的是使exit同步,也就是说在同一时刻只能由一个线程来修改exit的值

    2、使用interrupt()方法终止线程

    使用interrupt()方法来终端线程可分为两种情况:

    线程处于阻塞状态,如使用了sleep,同步锁的wait,socket的receiver,accept等方法时,会使线程处于阻塞状态。当调用线程的interrupt()方法时,系统会抛出一个InterruptedException异常,代码中通过捕获异常,然后break跳出循环状态,使线程正常结束。通常很多人认为只要调用interrupt方法线程就会结束,实际上是错的,一定要先捕获InterruptedException异常之后通过break来跳出循环,才能正常结束run方法。

     

    package com.gatsby.threadsafe;
    
    import android.os.Bundle;
    import android.util.Log;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            new MyThread().start();
        }
    
        class MyThread extends Thread {
            int i = 1;
            @Override
            public void run() {
                while (i < 100) {
                    Log.d("gatsby", "Thread.currentThread().getId()->"+Thread.currentThread().getId()+" i->" + (i++));
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;//捕获到异常之后,执行break跳出循环。
                    }
                }
            }
        }
    }

    线程未进入阻塞状态,使用isInterrupted()判断线程的中断标志来退出循环,当使用interrupt()方法时,中断标志就会置true,和使用自定义的标志来控制循环是一样的道理。

        // 定义开始和结束线程的方法,与按钮绑定
        public void goThread() {
            if (null == myThread) {
                myThread = new MyThread();
            }
            myThread.start();
        }
    
        private void stopThread() {
            if (null != myThread && myThread.isAlive()) {
                myThread.interrupt();
                myThread = null;
            }
        }
    package com.gatsby.threadsafe;
    
    import android.os.Bundle;
    import android.util.Log;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            new MyThread().start();
        }
    
        class MyThread extends Thread {
            int i = 1;
    
            @Override
            public void run() {
                while (i < 100) {
                    Log.d("gatsby", "Thread.currentThread().getId()->" + Thread.currentThread().getId() + " i->" + (i++));
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;//捕获到异常之后,执行break跳出循环。
                    }
                }
            }
        }
    }

    为什么要区分进入阻塞状态和和非阻塞状态两种情况了,是因为当阻塞状态时,如果有interrupt()发生,系统除了会抛出InterruptedException异常外,还会调用interrupted()函数,调用时能获取到中断状态是true的状态,调用完之后会复位中断状态为false,所以异常抛出之后通过isInterrupted()是获取不到中断状态是true的状态,从而不能退出循环,因此在线程未进入阻塞的代码段时是可以通过isInterrupted()来判断中断是否发生来控制循环,在进入阻塞状态后要通过捕获异常来退出循环。因此使用interrupt()来退出线程的最好的方式应该是两种情况都要考虑:

    public class ThreadSafe extends Thread {
        public void run() { 
            while (!isInterrupted()){ //非阻塞过程中通过判断中断标志来退出
                try{
                    Thread.sleep(5*1000);//阻塞过程捕获中断异常来退出
                }catch(InterruptedException e){
                    e.printStackTrace();
                    break;//捕获到异常之后,执行break跳出循环。
                }
            }
        } 
    }
  • 相关阅读:
    Excel导出
    上传进度基础
    git基本使用
    git学习记录
    Composer 扩展包安装方法
    selected多次点击不生效
    ajaxFileUpload的data数据带pre标签
    php-resque 简单的php消息队列
    git checkout 报错 refname 'origin/branch-name' is ambiguous
    MySQL单独存放表空间Innodb_file_per_table
  • 原文地址:https://www.cnblogs.com/crushgirl/p/12915062.html
Copyright © 2011-2022 走看看