Java убить или прекратить поток - PullRequest
3 голосов
/ 17 декабря 2010

Привет всем: По сути, мне нужно убить или остановить запуск потока, когда пользователь нажимает кнопку «Завершить». Этот поток проходит по списку массивов и отображает каждое событие в JTextArea. Требование заключается в том, что когда пользователь нажимает кнопку «Завершить», мне нужно прервать работающий поток и одновременно добавить новое событие «Завершение» в массив и разрешить ему снова запустить печать «Программирование завершения». Следующий код вроде «работает», но я получил исключение java.util.ConcurrentModificationException в консоли. Кто-нибудь может помочь?

public void startEvents()
    {
        terminate = false;
        worker = new Thread(new Runnable()
        {
            public void run()
            {
                Iterator<Event> it = eventList.iterator();

                while (it.hasNext())
                {
                    waitWhileSuspended();
                    terminatEvents();
                    Event ev = it.next();
                    try
                    {
                        Thread.sleep(ev.getDelayTime());
                    } catch (InterruptedException e1)
                    {
                        e1.printStackTrace();
                    }
                    jTextArea.append(ev.toString() + "\n");
                    it.remove();
                }
                jbStart.setEnabled(true);
                jmiStart.setEnabled(true);
                jbRestart.setEnabled(true);
                jmiRestart.setEnabled(true);
            }
        });
        worker.start();
    }
public void terminatEvents()
    {
        while(terminate)
        {
            Thread.yield();
            eventList.clear();
            eventList.add(new Terminate(delayTime));
            startEvents();

        }
    }

Ответы [ 5 ]

1 голос
/ 17 декабря 2010

Похоже, что вы изменяете список (очищаете его, затем добавляете новое событие Terminate), итерируя по нему.Вот почему вы получаете ConcurrentModificationException.

. Я бы посоветовал вам просто иметь terminate() метод в вашем объекте потока и вызывать его, чтобы остановить печать события в списке, ТОГДА печатать новое событие Terminate,без использования списка.

1 голос
/ 17 декабря 2010

Проблема в том, что вы изменяете список и одновременно зацикливаете его.Со стандартными списками поведение этого не определено, и это вызывает исключение.Посмотрите на пакет java.util.concurrent для коллекций, безопасных для многопоточного использования.

0 голосов
/ 17 декабря 2010

Я бы это сделал

public void run() {
  while (!isInterrupted()) {
    // actual working code goes here
  }
} // end of life for this thread

, а затем просто вызвал прерывание (), когда я хочу остановить поток.

0 голосов
/ 17 декабря 2010

Обычный способ остановить поток - установить некоторый изменяемый логический флаг, я вижу, что в вашем случае это поле terminate. Чтобы следовать нормальному шаблону, вы должны просто проверять этот флаг на каждой итерации, например while (!terminated && ...). Поток, который устанавливает флаг завершения, должен также поместить ваше конечное событие в какое-то поле, скажем, terminateEvent, которое вы должны проверить после цикла, если в этой точке значение true для завершения (то есть, если поток был завершен в отличие от обычного завершения). Конечно, доступ к terminateEvent должен быть синхронизирован (обратите внимание, что volatile, вероятно, здесь не будет работать).

Однако, поскольку у вас есть список событий для обработки, я бы предпочел следовать другому шаблону. Замените список параллельной очередью (хорошим примером является LinkedBlockingQueue), а затем, когда вам нужно завершить поток, вместо установки логического флага вы просто очищаете очередь и помещаете туда свое событие завершения. Поток обработки событий после обработки каждого события должен проверить, было ли это событием завершения (с помощью instanceof или какого-либо метода getEventClass ()), и если это так, просто разорвать цикл.

Обратите внимание, что поскольку в вашем потоке выполняются длительные операции, такие как Thread.sleep () и, возможно, waitWhileSuspended () (что бы это ни было, хотя оно может вам больше не понадобиться после переключения в очередь блокировки), вам нужно прерывать поток после помещения события завершения в очередь и обработки InterruptedException в потоке обработки событий в соответствии с логикой приложения. Например, вы должны решить, обрабатывать ли событие, если Thread.sleep () был прерван, или вместо этого переходить к следующей итерации.

0 голосов
/ 17 декабря 2010

У вас есть изменение коллекции из 2 потоков.По умолчанию коллекции не синхронизированы, следует использовать ключевое слово «Синхронизировано» или переключиться на synchronizedCollection http://download.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#synchronizedCollection(java.util.Collection)

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