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


79

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

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

那么,有谁知道停止线程的最佳方法是什么?

Answers:


90

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

这是一个很好的教程在这里


谢谢,我一直在寻找cancel()或stop()。
米洛什·切尔尼洛夫斯基

@MilošČernilovskýstop()方法已过时,您不应再使用它。
Alston

29

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

class WorkerThread extends Thread {
    volatile boolean running = true;

    public void run() {
        // Do work...
        if (!running) return;
        //Continue doing the work
    }
}

主要思想是不时检查该字段的值。当需要停止线程时,将其设置running为false。同样,正如克里斯指出的那样,您可以使用中断机制。

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


23

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

通常使用一个volatile boolean字段,当它设置为相应的值时,线程会定期检查并终止该字段。

不会使用aboolean来检查线程是否应该终止。如果您使用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,用于清除当前线程的中断状态。


2
在Android Studio中说,从未在相应的try块中引发异常'java.lang.InterruptedException'吗?
CraPo

1
@CraPo在while循环之前添加它:if (Thread.interrupted()) { throw new InterruptedException();}
Kosso

16

Thread.stop()不建议使用可用于停止线程的方法。有关更多信息,请参见;为什么不赞成使用Thread.stop,Thread.suspend和Thread.resume?

最好的选择是拥有一个线程本身要查询的变量,如果该变量等于某个值,则该线程自动退出。然后,当您希望线程退出时,可以在代码内操作变量。当然,您也可以使用AsyncTask代替。


4
AsyncTask并不是中断机制的真正替代,它更是一种与UI交互的工具。正如我在回答中指出的那样,如果您希望能够在执行期间停止它,则仍然必须在AsyncTask中实现与任何公共线程相同的机制。
马尔科姆

2

当前和不幸的是,我们无法做任何事情来停止线程...。

在我们可以调用的Matt答案中添加一些内容,interrupt()但这不会停止线程...仅当系统要终止某些线程时才告诉系统停止线程。其余的工作由系统完成,我们可以通过致电进行检查interrupted()

[ps:如果您真的要和interrupt()我一起去,我会要求您打电话后做一些短暂睡眠的实验interrupt()]


2

像这样尝试

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();

1

有两种首选的方法来停止线程。

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

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

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

0

我用这种方法。

Looper.myLooper().quit();

你可以试试。


0

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

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;



       }
   }

}

0

如果您的项目中有带有处理程序的线程类,则从片段类之一开始时如果要停止,这里的解决方案是如何停止并避免在片段从堆栈中移出时使应用程序崩溃。

这段代码在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")



    }
}

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


0

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

领域:

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;

2
这不会停止Thread,只会停止yourWork();被调用。要对此进行测试,您可以在Log下方添加public void run() {
KRK,

@KRK我知道这个!而且我确实发布了此答案,因为当您只想停止某些操作并重新启动它而无需执行任何操作时,它非常有用。
哈迪笔记

@HadiNote KRK是正确的。您在回答中说明If you want to stop the thread you should make the below field: private boolean runningThread = false;。这是不正确的。
pookie

0

我的要求与问题略有不同,但这仍然是停止线程执行其任务的一种有用方法。我要做的就是在退出屏幕时停止线程,并在返回屏幕时继续执行。

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

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;
    }

0

我们知道Thread.stop()在JAVA中已被弃用,Thread.stop在后台调用线程上的interrupt()方法来停止它,因此Interrupt会从保持线程等待的方法中抛出其他一些线程在执行完成后通知。如果在线程执行过程中未对其进行处理,则中断将不会对线程造成任何影响,if(Thread.interrupted())return; 因此,总的来说,我们基本上需要管理线程的启动和停止,就像调用start()方法一样,例如在方法Thread.start()while(true)内部启动run()。线程并在每次迭代中检查中断状态,然后从线程返回。

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

  1. 该线程尚未从run()返回。
  2. 线程拥有的任何对象都是可访问的。(这暗示着将空值/处置GC要做的其余工作的引用)

-2

在任何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;
    }
}
}

这对我毫无问题。


11
Thread变量设置为null不会停止线程。将参数设置为nullinsidestopThread完全是浪费时间。
泰德·霍普

2
这怎么可能停止线程?为什么对此有正面的赞成票?
2015年

1
这不会停止线程。线程仍在运行,并且为该线程的实例分配了null,从而无法控制该线程,因为您丢失了该实例(该实例将一直运行,直到进程结束)
Teocci
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.