【问题标题】:Android - Best and safe way to stop threadAndroid - 停止线程的最佳和安全方法
【发布时间】:2012-01-20 07:11:54
【问题描述】:

我想知道在 Android 中停止线程的最佳方法是什么。我知道我可以使用AsyncTask 代替它,并且有一个cancel() 方法。在我的情况下,我必须使用Threads。这是我使用Thread的方式:

Runnable runnable = new Runnable() {
        @Override
        public void run() {
            //doing some work
        }
    };
new Thread(runnable).start();

那么,有没有人知道哪个是停止线程的最佳方法?

【问题讨论】:

    标签: android thread-safety


    【解决方案1】:

    你应该让你的线程支持中断。基本上,您可以调用yourThread.interrupt() 来停止线程,并且在您的run() 方法中,您需要定期检查Thread.interrupted() 的状态

    有一个很好的教程here

    【讨论】:

    • 谢谢,我一直在寻找 cancel() 或 stop()。
    • @MilošČernilovský stop() 方法已弃用,您不应再使用它。
    【解决方案2】:

    这种情况与标准 Java 没有任何不同。您可以使用标准方式停止线程:

    class WorkerThread extends Thread {
        volatile boolean running = true;
    
        public void run() {
            // Do work...
            if (!running) return;
            //Continue doing the work
        }
    }
    

    主要思想是不时检查字段的值。当您需要停止线程时,将running 设置为false。此外,正如 Chris 所指出的,您可以使用中断机制。

    顺便说一句,当您使用 AsyncTask 时,您的方法不会有太大差异。唯一的区别是您必须从您的任务中调用isCancel() 方法,而不是使用特殊字段。如果你调用cancel(true),但不实现这个机制,线程仍然不会自行停止,它会运行到最后。

    【讨论】:

      【解决方案3】:

      在 Android 上,应用与普通 Java 环境相同的规则。 在 Java 中,线程不会被杀死,但线程的停止是以 合作方式 完成的。线程被要求终止,然后线程可以正常关闭。

      通常使用volatile boolean 字段,线程会定期检查并在设置为相应值时终止。

      不会使用boolean 来检查线程是否应该终止。如果您使用volatile 作为字段修饰符,这将工作可靠,但如果您的代码变得更复杂,因为在while 循环中使用其他阻塞方法,则可能会发生,您的代码将不会终止 完全没有,或者至少 需要更长的时间,如您所愿。

      某些阻塞库方法支持中断。

      每个线程都有一个布尔标志中断状态,你应该使用它。可以这样实现:

      public void run() {
      
         try {
            while(!Thread.currentThread().isInterrupted()) {
               // ...
            }
         } catch (InterruptedException consumed)
            /* Allow thread to exit */
         }
      
      }
      
      public void cancel() { interrupt(); }
      

      源代码取自Java Concurrency in Practice。由于cancel() 方法是公开的,您可以让另一个线程根据需要调用此方法。

      还有一个名字不好的静态方法interrupted,它会清除当前线程的中断状态。

      【讨论】:

      • 在 Android Studio 中它说,异常 'java.lang.InterruptedException' 永远不会在相应的 try 块中引发?
      • @CraPo 在 while 循环之前添加:if (Thread.interrupted()) { throw new InterruptedException();}
      【解决方案4】:

      可用于停止线程的Thread.stop() 方法已被弃用;欲了解更多信息,请参阅; Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?.

      最好的办法是拥有一个线程本身会参考的变量,如果变量等于某个值,它会自动退出。然后,当您希望线程退出时,您可以在代码中操作变量。当然,您也可以改用AsyncTask

      【讨论】:

      • AsyncTask 并不是真正的中断机制的替代品,它更像是一种与 UI 交互的工具。正如我在回答中指出的那样,如果您希望能够在执行期间停止它,您仍然必须在 AsyncTask 中实现与在任何公共线程中相同的机制。
      【解决方案5】:

      目前很遗憾,我们无法做任何事情来停止线程......

      在 Matt 的回答中添加一些内容,我们可以调用 interrupt() 但这不会停止线程...只是告诉系统在系统想要终止某些线程时停止线程。其余由系统完成,我们可以调用interrupted()查看。

      [附言。 : 如果你真的要去interrupt(),我会要求你在致电interrupt()后做一些短暂睡眠的实验]

      【讨论】:

        【解决方案6】:

        这样试试

        Thread thread = new Thread() {
            @Override
            public void run() {
                Looper.prepare();   
                while(true){ 
                    Log.d("Current Thread", "Running"); 
                    try{
                       Thread.sleep(1000);
                    }catch(Exeption exception){ }
                }
            }
        };
        
        thread.start();
        thread.interrupt();
        

        【讨论】:

          【解决方案7】:

          有以下 2 种首选方式来停止线程。

          1. 创建一个 volatile 布尔变量并将其值更改为 false 并检查线程内部。

            volatile isRunning = false;
            
            public void run() {
            if(!isRunning) {return;}       
            
            }
            
          2. 或者你可以使用可以在线程内接收的interrupt()方法。

            SomeThread.interrupt();
            
            public void run() {
            if(Thread.currentThread.isInterrupted()) {return;}
             }
            

          【讨论】:

            【解决方案8】:

            我用过这个方法。

            Looper.myLooper().quit();
            

            你可以试试。

            【讨论】:

              【解决方案9】:

              问题是您需要检查线程是否正在运行!?

              字段:

              private boolean runningThread = false;
              

              在线程中:

              new Thread(new Runnable() {
                          @Override
                          public void run() {
                              while (true) {
                                  try {
                                      Thread.sleep((long) Math.floor(speed));
                                      if (!runningThread) {
                                          return;
                                      }
                                      yourWork();
                                  } catch (InterruptedException e) {
                                      e.printStackTrace();
                                  }
                              }
                          }
                      }).start();
              

              如果你想停止线程,你应该做下面的字段

              private boolean runningThread = false;
              

              【讨论】:

              • 这不会阻止Thread,它只会阻止yourWork(); 被调用。要对此进行测试,您可以在public void run() { 下方添加Log
              • @KRK 我知道这一点!我确实发布了这个答案,因为当您只想停止某些事情并重新启动它而不做任何线程时,它非常有用。
              • @HadiNote KRK 是正确的。您在回答中声明If you want to stop the thread you should make the below field: private boolean runningThread = false;。这是不正确的。
              【解决方案10】:

              我的要求与问题略有不同,但这也是停止线程执行其任务的有用方法。我想做的就是在退出屏幕时停止线程并在返回屏幕时恢复。

              根据 Android 文档,这将是 API 15 已弃用的 stop 方法的提议替代

              stop 的许多用法应该替换为简单地修改某些内容的代码 变量来指示目标线程应该停止运行。这 目标线程应该定期检查这个变量,并从 如果变量指示它以有序的方式运行它的方法 是停止运行。

              我的线程类

                 class ThreadClass implements Runnable {
                          ...
                                @Override
                                      public void run() {
                                          while (count < name.length()) {
              
                                              if (!exited) // checks boolean  
                                                {
                                                 // perform your task
                                                                   }
                          ...
              

              OnStop 和 OnResume 看起来像这样

                @Override
                  protected void onStop() {
                      super.onStop();
                      exited = true;
                  }
              
                  @Override
                  protected void onResume() {
                      super.onResume();
                      exited = false;
                  }
              

              【讨论】:

                【解决方案11】:

                我们知道 Thread.stop() 在 JAVA 中已被弃用,在引擎盖下 Thread.stop 调用线程上的 interrupt() 方法来停止它,Interrupt 意味着从保持执行完成后等待某个其他线程通知的线程。如果在线程执行过程中不处理中断,则不会对线程造成任何影响,例如if(Thread.interrupted())return; 所以,总而言之,我们需要基本管理线程的启动和停止,例如调用Thread.start() 之类的Thread.start() 方法在线程的run() 方法内启动while(true),并在每次迭代中检查中断状态并从线程返回。

                请注意,以下情况线程不会死:

                1. 线程尚未从 run() 返回。
                2. 线程拥有的任何对象都可以访问。 (这提示为 GC 将引用清空/处置以完成其余工作)

                【讨论】:

                  【解决方案12】:

                  这对我有用。在主要活动中引入一个静态变量,并定期检查我的做法如下。

                  public class MainActivity extends AppCompatActivity {
                  
                  
                  //This is the static variable introduced in main activity
                  public static boolean stopThread =false;
                  
                  
                  
                    protected void onCreate(Bundle savedInstanceState) {
                  
                      super.onCreate(savedInstanceState);
                      setContentView(R.layout.activity_main);
                  
                      Thread thread = new Thread(new Thread1());
                      thread.start();
                  
                      Button stp_thread= findViewById(R.id.button_stop);
                  
                      stp_thread.setOnClickListener(new Button.OnClickListener(){
                             @Override
                             public void onClick(View v){
                                stopThread = true;
                             }
                  
                       }
                  
                    }
                  
                  
                    class Thread1 implements Runnable{
                  
                          public void run() {
                  
                          // YOU CAN DO IT ON BELOW WAY 
                          while(!MainActivity.stopThread) {
                               Do Something here
                          }
                  
                  
                          //OR YOU CAN CALL RETURN AFTER EVERY LINE LIKE BELOW
                  
                          process 1 goes here;
                  
                          //Below method also could be used
                          if(stopThread==true){
                              return ;
                          }
                          // use this after every line
                  
                  
                  
                          process 2 goes here;
                  
                  
                          //Below method also could be used
                          if(stopThread==true){
                              return ;
                          }
                          // use this after every line
                  
                  
                          process 3 goes here;
                  
                  
                          //Below method also could be used
                          if(stopThread==true){
                              return ;
                          }
                          // use this after every line
                  
                  
                          process 4 goes here;
                  
                  
                  
                         }
                     }
                  
                  }
                  

                  【讨论】:

                    【解决方案13】:

                    如果您的项目中存在带有处理程序的线程类,则当您从片段类之一开始时,如果您想在此处停止,则解决方案是如何在片段从堆栈中删除时停止并避免应用程序崩溃。

                    此代码在 Kotlin 中。效果很好。

                    class NewsFragment : Fragment() {
                    
                        private var mGetRSSFeedsThread: GetRSSFeedsThread? = null
                    
                        private val mHandler = object : Handler() {
                    
                            override fun handleMessage(msg: Message?) {
                    
                    
                                if (msg?.what == GetRSSFeedsThread.GETRSSFEEDSTHREAD_SUCCESS) {
                                    val updateXMLdata = msg.obj as String
                                    if (!updateXMLdata.isNullOrEmpty())
                                        parseUpdatePager(CommonUtils.getJSONObjectFromXML(updateXMLdata).toString())
                    
                                } else if (msg?.what == GetRSSFeedsThread.GETRSSFEEDSTHREAD_SUCCESS) {
                                    BaseActivity.make_toast(activity, resources.getString(R.string.pleaseTryAgain))
                                }
                    
                            }
                        }
                        private var rootview: View? = null;
                        override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
                            rootview = inflater?.inflate(R.layout.fragment_news, container, false);
                    
                            news_listView = rootview?.findViewById(R.id.news_listView)
                            mGetRSSFeedsThread = GetRSSFeedsThread(this.activity, mHandler)
                    
                    
                            if (CommonUtils.isInternetAvailable(activity)) {
                                mGetRSSFeedsThread?.start()
                            }
                    
                    
                            return rootview
                        }
                    
                        override fun onCreate(savedInstanceState: Bundle?) {
                            super.onCreate(savedInstanceState)
                            setHasOptionsMenu(true);
                    
                        }
                    
                    
                    
                        override fun onAttach(context: Context?) {
                            super.onAttach(context)
                            println("onAttach")
                        }
                    
                        override fun onPause() {
                            super.onPause()
                            println("onPause fragment may return to active state again")
                    
                            Thread.interrupted()
                    
                        }
                    
                        override fun onStart() {
                            super.onStart()
                            println("onStart")
                    
                        }
                    
                        override fun onResume() {
                            super.onResume()
                            println("onResume fragment may return to active state again")
                    
                        }
                    
                        override fun onDetach() {
                            super.onDetach()
                            println("onDetach fragment never return to active state again")
                    
                        }
                    
                        override fun onDestroy() {
                            super.onDestroy()
                    
                            println("onDestroy fragment never return to active state again")
                           //check the state of the task
                            if (mGetRSSFeedsThread != null && mGetRSSFeedsThread?.isAlive!!) {
                                mGetRSSFeedsThread?.interrupt();
                            } else {
                    
                            }
                    
                        }
                    
                        override fun onDestroyView() {
                            super.onDestroyView()
                            println("onDestroyView fragment may return to active state again")
                    
                    
                    
                        }
                    
                        override fun onStop() {
                            super.onStop()
                            println("onStop fragment may return to active state again")
                    
                    
                    
                        }
                    }
                    

                    当您从当前片段切换到任何其他片段或活动时,上述代码会停止正在运行的线程。当您返回当前片段时它也会重新创建

                    【讨论】:

                      【解决方案14】:

                      在任何 Activity 类中,您都可以创建一个将 NULL 分配给线程实例的方法,该方法可用作停止线程执行的已弃用的 stop() 方法的替代方法:

                      public class MyActivity extends Activity {
                      
                      private Thread mThread;  
                      
                      @Override
                      public void onCreate(Bundle savedInstanceState)
                      {
                          super.onCreate(savedInstanceState);
                          setContentView(R.layout.main);
                      
                      
                              mThread =  new Thread(){
                              @Override
                              public void run(){
                                  // Perform thread commands...
                          for (int i=0; i < 5000; i++)
                          {
                            // do something...
                          }
                      
                          // Call the stopThread() method.
                                  stopThread(this);
                                }
                              };
                      
                          // Start the thread.
                              mThread.start(); 
                      }
                      
                      private synchronized void stopThread(Thread theThread)
                      {
                          if (theThread != null)
                          {
                              theThread = null;
                          }
                      }
                      }
                      

                      这对我来说没有问题。

                      【讨论】:

                      • Thread 变量设置为null 不会停止线程。在stopThread 中将参数设置为null 完全是浪费时间。
                      • 这怎么可能停止线程?为什么在哪里有赞成票?
                      • 这不会停止线程。线程仍在运行,这会将 null 分配给 Thread 的实例,从而无法控制该线程,因为您丢失了实例(它将继续运行直到进程结束)
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-07-10
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-12-03
                      • 1970-01-01
                      • 2019-11-15
                      相关资源
                      最近更新 更多