Хорошая практика для многопоточности - PullRequest
7 голосов
/ 21 марта 2012

У меня есть приложение, в котором при «игровой» статистике запускается пара разных потоков. Я начинаю темы так:

Thread thread = new Thread(new Runnable()
{
    public void run()
    {
        //...
    }
});

thread.setName("killMeAtEnd");
thread.start();

Позже, когда игра заканчивается, у меня есть метод dispose () внутри игры, который сортирует все запущенные потоки и завершает все потоки с именем «killMeAtEnd». Мой вопрос, это хорошая практика? Мое намерение состоит в том, чтобы мое приложение работало быстро и не мешало работе. По моему опыту, «зависшие» потоки, как правило, замедляют работу телефона до тех пор, пока приложение не будет закрыто. Есть лучший способ сделать это? Стоит ли беспокоиться об этом?

EDIT:

Вот мой dispose(), если кому-то было интересно. Этот код находится в классе Game.

public void dispose()
{
    Thread threads[] = (Thread[])Thread.getAllStackTraces().keySet().toArray();
    for(int x=0;x<threads.length;x++)
    {
        Thread thread = threads[x];
        if(thread.getName().equalsIgnoreCase(KILL))
        {
            try
            {
                thread.interrupt();
            }catch(Exception e){Log.e(Viewer.GAME,Log.getStackTraceString(e));}
            thread = null;
        }
    }
}

public static final String KILL = "endOnDispose";

Ответы [ 3 ]

4 голосов
/ 21 марта 2012

У вас правильная идея, но есть некоторые области для улучшения:

  1. Вместо того, чтобы запрашивать систему для всех запущенных потоков, просто добавляйте свои потоки в список при каждом их создании.Затем вы можете завершить все созданные вами потоки или дождаться их завершения (присоединения).
  2. Прерывание прерывает только поток в состоянии блокировки, поэтому вам необходимо иметь дополнительный флаг, который поток проверяет периодически (т.е. послекаждый «рабочий цикл»).
  3. Поймать исключение прерывания в вашем потоке и обработать его (т.е. завершить корректно).
3 голосов
/ 21 марта 2012

Это не обязательно плохое решение, но есть несколько проблем:

  • Если ваши потоки являются рабочими потоками того типа, которые выполняют одну задачудо завершения, вероятно, существует лучшая конструкция, в которой поток заканчивается сам.Другими словами, возможно, существует лучший поток выполнения, который не требует уничтожения в конце.

  • Когда вы говорите «перебрать все работающие потоки ...», Я полагаю, вы смотрите на все запущенные темы в JVM?как в чем-то вроде этого ТАКОГО вопроса ?Если это так, то почему бы вам не оставить ссылку на все потоки, которыми владеет ваша игра, а затем специально убить их?В отличие от просто поиска "killMeAtEnd";Я не могу думать о том, как ваша стратегия может пойти не так, но, кажется, немного чище следить за вашими потоками.

Это определенно хорошая практика - поддерживать чистоту потоков.Если ваши потоки делают что-то менее ориентированное на конкретные задачи (например, ожидают сетевой ввод или что-то в этом роде), то мое первое предложение несколько неуместно.Я бы просто посоветовал быть очень осторожным в разработке того, как вы сохраняете свои потоки чистыми, потому что ошибки с потоками могут быть большой болью.

0 голосов
/ 21 марта 2012

Класс ExecutorService уже существует для решения подобных проблем.

Выполните все задачи потоков для ExecutorService.

Когда игра закончится, закройте ExecutorService с помощью shutdownNow.Это прервет все потоки в ExecutorService.Затем вы можете создать новый ExecutorService при запуске новой игры.

Если количество потоков фиксировано, вы можете использовать Executors.newFixedThreadPool () для создания ExecutorService.

Если числоthreads является переменной, вы можете использовать Executors.newCachedThreadPool для создания ExecutorService.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...