我通过以下方式创建了一个线程服务:
public class TCPClientService extends Service{ ... @Override public void onCreate() { ... Measurements = new LinkedList(); 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); } } } ... }
关闭应用程序后,手机工作速度非常慢,我想这是由于线程终止失败.
有没有人知道在终止应用程序之前终止所有线程的最佳方法是什么?
附录:Android框架为一次性工作,后台工作等提供了许多帮助,这可能比在许多情况下尝试滚动自己的线程更可取.如下文所述,AsyncTask是一个很好的起点.我鼓励读者在开始考虑做自己的线程之前先研究框架规定.
您发布的代码示例中有几个问题我将按顺序解决:
1)Thread.stop()已经被弃用了一段时间,因为在某些情况下它可能会使因变量处于不一致状态.有关更多详细信息,请参阅此Sun答案页面(编辑:该链接现已停止,请参阅此页面了解为何不使用Thread.stop()).停止和启动线程的首选方法如下(假设您的线程将无限期地运行):
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变量,也可以通过互斥锁等)并在你的线程逻辑中,使用这种通信方法来检查你是否应该提前退出,清理等.
2)您的测量列表可以由多个线程(事件线程和您的用户线程)同时访问,而无需任何同步.看起来您不必滚动自己的同步,可以使用BlockingQueue.
3)您在发送线程的每次迭代中创建一个新的Socket.这是一项相当重要的操作,只有在您预计测量非常罕见(例如一小时或更短时间)时才真正有意义.要么你想要一个不会在线程的每个循环中重新创建的持久套接字,要么你想要一次性运行,你可以"触发并忘记"创建套接字,发送所有相关数据并完成.(关于使用持久性Socket的快速说明,阻塞的套接字方法,如读取,不能被Thread.interrupt()中断,所以当你想要停止线程时,你必须关闭套接字以及调用中断)
4)除非你希望在其他地方捕获它,否则从Thread中抛出你自己的异常几乎没有意义.更好的解决方案是记录错误,如果不可恢复,请停止该线程.一个线程可以使用代码(在与上面相同的上下文中)自行停止:
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(true).这会将线程标记为守护程序线程,这意味着如果没有运行非守护程序线程(例如,如果您的应用程序退出),VM将确保自动销毁它.
遵循线程的最佳做法应确保您的应用程序不会挂起或放慢手机速度,尽管它们可能非常复杂:)
实际上,您不需要如上所述的"runner"变量,例如:
while (!interrupted()) { try { Thread.sleep(1000); } catch (InterruptedException ex) { break; } }
但一般来说,坐在Thread.sleep()循环中是一个非常糟糕的主意.
查看新1.5 API中的AsyncTask API.它可能比使用服务更优雅地解决您的问题.你的手机变慢了,因为服务永远不会关闭 - 没有任何东西可以导致服务自杀.