Ответ 1
Добавление. Рамки для Android предоставляют много помощников для одноразовой работы, фоновой работы и т.д., что может быть предпочтительнее, чем пытаться перевернуть собственный поток во многих случаях. Как упоминалось в следующем сообщении, AsyncTask - хорошая отправная точка для изучения. Я призываю читателей заглянуть в рамки положений, прежде чем даже начать думать о том, чтобы делать свои собственные потоки.
В приведенном вами примере кода есть несколько проблем, которые я адресую по порядку:
1) Thread.stop() устарел уже довольно давно, так как в некоторых случаях он может оставить зависимые переменные в непоследовательных состояниях. Подробнее см. эту страницу ответа Sun (Edit: эта ссылка теперь мертва, см. на этой странице, почему бы не использовать 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) после создания и до того, как вы начнете поток. Это флага потока как поток демона, то есть виртуальная машина будет гарантировать, что она будет автоматически уничтожена, если нет потоков не-daemon (например, если ваше приложение завершает работу).
Соблюдение лучших практик в отношении Threads должно гарантировать, что ваше приложение не зависает или замедляет работу телефона, хотя они могут быть довольно сложными:)