在哪里停止/销毁机器人服务类主题?机器人、主题

2023-09-12 00:23:20 作者:佩服许仙敢曰蛇

我创建了一个线程服务方式如下:

I have created a threaded service the following way:

public class TCPClientService extends Service{  
...

@Override
public void onCreate() {
    ...
    Measurements = new LinkedList<String>();
    enableDataSending();    
}

@Override
public IBinder onBind(Intent intent) {
    //TODO: Replace with service binding implementation
    return null;
}

@Override
public void onLowMemory() {
    Measurements.clear();
    super.onLowMemory();
}

@Override
public void onDestroy() {
    Measurements.clear();
    super.onDestroy();
    try {
        SendDataThread.stop();
    } catch(Exception e){
        ...     
    }

}

private Runnable backgrounSendData = new Runnable() {

    public void run() {
        doSendData();
    }
};

private void enableDataSending() {
    SendDataThread = new Thread(null, backgrounSendData, "send_data");
    SendDataThread.start();
}

 private void addMeasurementToQueue() {
     if(Measurements.size() <= 100) {
         String measurement = packData();
         Measurements.add(measurement);
     }
 }

 private void doSendData() {
     while(true) {
         try {      
             if(Measurements.isEmpty()) {
                 Thread.sleep(1000);
                 continue;
             }
             //Log.d("TCP", "C: Connecting...");
             Socket socket = new Socket();
             socket.setTcpNoDelay(true);
             socket.connect(new InetSocketAddress(serverAddress, portNumber), 3000);
             //socket.connect(new InetSocketAddress(serverAddress, portNumber));
             if(!socket.isConnected()) {
                 throw new Exception("Server Unavailable!");
             }
             try {
                 //Log.d("TCP", "C: Sending: '" + message + "'");
                 PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);
                 String message = Measurements.remove();
                 out.println(message);
                 Thread.sleep(200);
                 Log.d("TCP", "C: Sent.");
                 Log.d("TCP", "C: Done.");
                 connectionAvailable = true;              
             } catch(Exception e) {
                 Log.e("TCP", "S: Error", e);
                 connectionAvailable = false;
             } finally {
                 socket.close();
                 announceNetworkAvailability(connectionAvailable);
             }
         } catch (Exception e) {
             Log.e("TCP", "C: Error", e);
             connectionAvailable = false;
             announceNetworkAvailability(connectionAvailable);
         }
    }
}

...
}

在我关闭应用程序手机的工作原理很慢,我想这是因为线程终止失败。

After I close the application the phone works really slow and I guess it is due to thread termination failure.

有谁知道什么是终止应用程序之前终止所有线程的最佳方法是什么?

Does anyone know what is the best way to terminate all threads before terminating the application?

推荐答案

附录:Android框架提供了许多帮助者一次性的工作,工作背景等,这可能是preferable在试图推出自己的线程在许多情况下。正如一个后下,AsyncTask的是一个很好的出发点考虑。我鼓励读者甚至开始考虑做自己的线程之前寻找到的框架规定第一。

Addendum: The Android framework provides many helpers for one-off work, background work, etc, which may be preferable over trying to roll your own thread in many instances. As mentioned in a below post, AsyncTask is a good starting point to look into. I encourage readers to look into the framework provisions first before even beginning to think about doing their own threading.

有你贴我会在订单code样品中几个问题:

There are several problems in the code sample you posted I will address in order:

1)使用Thread.stop()已至此pcated很长一段时间,因为它可以留在某些情况下不一致的状态因变量去$ P $。请参见这个孙答案页面了解更多详情(编辑:这个链接现在死了,看到这个页面为什么不使用Thread.stop()以)。停止和启动一个线程的preferred方法如下(假设你的线程将运行有点无限期):

1) Thread.stop() has been deprecated for quite some time now, as it can leave dependent variables in inconsistent states in some circumstances. See this Sun answer page for more details ( that link is now dead, see this page for why not to use Thread.stop()). A preferred method of stopping and starting a thread is as follows (assuming your thread will run somewhat indefinitely):

private volatile Thread runner;

public synchronized void startThread(){
  if(runner == null){
    runner = new Thread(this);
    runner.start();
  }
}

public synchronized void stopThread(){
  if(runner != null){
    Thread moribund = runner;
    runner = null;
    moribund.interrupt();
  }
}

public void run(){
  while(Thread.currentThread() == runner){
    //do stuff which can be interrupted if necessary
  }
}

这是如何阻止一个线程只是一个例子,但外卖的是,你有责任退出线程就像你的任何其他方法。保持跨线程通信电子的方法(在这种情况下,volatile变量,也可以通过一个互斥体等),你的线程逻辑中,使用通信的方法来检查,如果你要提前退场,清理等。

This is just one example of how to stop a thread, but the takeaway is that you are responsible for exiting a thread just as you would any other method. Maintain a method of cross thread communcation (in this case a volatile variable, could also be through a mutex, etc) and within your thread logic, use that method of communication to check if you should early exit, cleanup, etc.

2)你的测量列表是由多个线程(事件线程和您的用户线程)在同一时间访问而没有任何同步。它看起来像你没有推出自己的同步,可以使用的的BlockingQueue 。

2) Your measurements list is accessed by multiple threads (the event thread and your user thread) at the same time without any synchronization. It looks like you don't have to roll your own synchronization, you can use a BlockingQueue.

3)您正在创建一个新的Socket您发送线程的每一次迭代。这是一个相当重量级的运作,只有真正意义,如果你期望的测量是非常罕见的(说的是一个小时或更少)。要么你想要的是不是重新创建线程的每个循环中的持久套接字,或者你想有一个一杆可运行你可以射后不理这将创建一个套接字,将所有相关数据,并完成。 (快速注意有关使用一个持久的插座,插座的方法哪个块,如阅读,不能用了Thread.interrupt()中断,所以当你要停止线程,你必须关闭插座以及调用中断)

3) You are creating a new Socket every iteration of your sending Thread. This is a rather heavyweight operation, and only really make sense if you expect measurements to be extremely infrequent (say one an hour or less). Either you want a persistent socket that is not recreated every loop of the thread, or you want a one shot runnable you can 'fire and forget' which creates a socket, sends all relevant data, and finishes. (A quick note about using a persistent Socket, socket methods which block, such as reading, cannot be interrupted by Thread.interrupt(), and so when you want to stop the thread, you must close the socket as well as calling interrupt)

4)是从一个线程中,除非你希望抓住它其他地方抛出自己的异常的小点。一个更好的解决方案是记录错误,如果它是无法收回的,停止线程。一个线程可以自行停止与code等(在相同的情况下同上):

4) There is little point in throwing your own exceptions from within a Thread unless you expect to catch it somewhere else. A better solution is to log the error and if it is irrecoverable, stop the thread. A thread can stop itself with code like (in the same context as above):

public void run(){
    while(Thread.currentThread() == runner){
      //do stuff which can be interrupted if necessary

      if(/*fatal error*/){
        stopThread();
        return; //optional in this case since the loop will exit anyways
      }
    }
  }

最后,如果你想确保线程退出与应用程序的其余部分,不管是什么,一个好的方法是创建后调用Thread.setDaemon(真),并启动线程之前。这标志线程作为守护线程,这意味着VM将确保它如果没有运行非守护线程(例如,如果你的应用程序退出)自动销毁。

Finally, if you want to be sure a thread exits with the rest of your application, no matter what, a good technique is to call Thread.setDaemon(true) after creation and before you start the thread. This flags the thread as a daemon thread, meaning the VM will ensure that it is automatically destroyed if there are no non-daemon threads running (such as if your app quits).

服从的最佳实践与问候的线程应该确保你的应用程序不挂或减慢了电话,虽然他们可以说是相当复杂的:)

Obeying best practices with regards to Threads should ensure that your app doesn't hang or slow down the phone, though they can be quite complex :)