Android - 停止线程的最佳和安全方法

Posted

技术标签:

【中文标题】Android - 停止线程的最佳和安全方法【英文标题】:Android - Best and safe way to stop thread 【发布时间】: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();

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

【问题讨论】:

【参考方案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 种首选方式来停止线程。

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

    volatile isRunning = false;
    
    public void run() 
    if(!isRunning) return;       
    
    
    

    或者你可以使用可以在线程内接收的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),并在每次迭代中检查中断状态并从线程返回。

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

    线程尚未从 run() 返回。 线程拥有的任何对象都可以访问。 (这提示为 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 的实例,从而无法控制该线程,因为您丢失了实例(它将继续运行直到进程结束)

以上是关于Android - 停止线程的最佳和安全方法的主要内容,如果未能解决你的问题,请参考以下文章

从分离线程停止主游戏循环的最佳方法

Android如何停止线程的方式

停止正在运行的线程的安全方法是啥?

1.7停止线程

线程的停止和暂停

Android 线程和处理程序没有停止