Как остановить один и тот же поток от запуска нескольких экземпляров - PullRequest
2 голосов
/ 08 сентября 2011

У меня есть поток демона, который запускается при открытии страницы.Затем поток останавливается, когда страница закрывается.Итак, в моем классе, который содержит поток, я создал его следующим образом:

class A {
 private static volatile boolean isStopped=false;

 //this method is called then the page is loaded
 public void testListener() {
   Thread listener = new Thread(new Runnable() {
      public void run() {
       while(!isStopped) {
        //perform listener event
       try {
         //after every event sleep for a while
         Thread.sleep(1000 *2)
       } catch(InterruptedException e){}
      }
     }
    });
 }
 listener.setName("Test-Server-Daemon");
 listener.setDaemon(true);
 listener.start();

 // reset back to false so thread can be restarted when the page load event,
 // call this method instance
 if (isStopped) {
   isStopped=false;
 }
}

 /**This is called when page is closed**/
 public static void stopListener() {
   isStopped=true;
  }
}

После исследования я заметил, что когда страница закрывается и не открывается снова, скажем, с интервалом в 30 секунд, потокграциозно остановился.

Но когда страница закрывается и открывается снова, скажем, с интервалом в 2 секунды, старый поток не останавливается и, следовательно, запускается одновременно с новым.

И, как вы можете видеть из рисунка ниже, у меня снова открывается та же тема, когда я закрываю и быстро открываю страницу.

Кто-нибудь знает, как предотвратить это?

Я пытался использовать поток interrupt, где я сбрасывал мьютекс, но без радости.

РЕДАКТИРОВАНИЕ:

isStopped равно volatile.

enter image description here

Ответы [ 7 ]

2 голосов
/ 08 сентября 2011

Чтобы следовать из ответа @ Jordão, переменная isStopped должна быть для каждого потока.Я бы порекомендовал использовать что-то вроде AtomicBoolean и изменить код вашего потока примерно так:

public AtomicBoolean testListener() {
    final AtomicBoolean isStopped = new AtomicBoolean(false);
    Thread listener = new Thread(new Runnable() {
        public void run() {
            while(!isStopped.get()) {
                ...
            }
        }
    });
    listener.setName("Test-Server-Daemon");
    listener.setDaemon(true);
    listener.start();
    return isStopped;
}

Затем вернувшись в свой контроллер страницы, вы можете сделать:

AtomicBoolean isStopped = testListener();
// do the page stuff
...
// when done stop the thread
isStopped.set(true);
2 голосов
/ 08 сентября 2011

Возможно, вы переопределяете значение isStopped с помощью false до , когда старый поток может увидеть, что он должен остановиться.Проблема в следующем:

if(isStopped) 
{
  isStopped=false;  
}

Вам лучше изолировать свой код: создайте отдельные экземпляры A для каждого потока и сделайте isStopped полем volatile экземпляра (не static).И удали этот блок кода ...

1 голос
/ 08 сентября 2011

Попробуйте использовать AtomicBoolean вместо логического поля.Используйте метод compareAndSet;дайте мне знать, если вам нужно больше разъяснений, поскольку javadocs весьма полезны.

1 голос
/ 08 сентября 2011

Если ваш флаг isStopped не установлен в течение хотя бы 2 секунд, ваш поток может спать, когда это произойдет.Гораздо более простое решение состоит в том, чтобы избежать запуска / остановки потока, поскольку это может привести к дополнительным накладным расходам, поскольку это экономит (это, безусловно, усложняет проблему)

Это то, что я хотел бы сделать, это запустить поток один и только один раз.

public void run() {
   try {
     while(true) {
       if(!isStopped) {
         //perform listener event
       }
       //after every event sleep for a while
       Thread.sleep(1000 *2);
     }
   } catch(InterruptedException e){}
}

Устанавливая флаг, он перестает работать, но поток продолжает проверять.

0 голосов
/ 09 сентября 2011

Я бы использовал для этого java.util.concurrent.ScheduledExecutorService .Он будет управлять потоком и расписанием задачи.

Например:

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class Scheduler {

static ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

static ScheduledFuture<?> future;

// called when the page is opened
public static void open() {
    future = service.scheduleAtFixedRate(new Runnable() {
        public void run() {
            //perform listener event
        }
    }, 0, 2, TimeUnit.SECONDS); // every 2 seconds


}

// called when the page is closed
public static void close() {
    // stop listener event
    future.cancel(true);
    future = null;
}

}

0 голосов
/ 08 сентября 2011

Переместите ваше создание за пределы вашего метода и сделайте его статичным.Эта гарантия, у вас будет только один экземпляр этой темы.

private static Thread listener;

Как только это будет сделано, вы можете добавить это к своему методу:

if(listener.isAlive()) try { Thread.sleep(100); } catch (InterruptedException ie) {}

listener = new Thread(new Runnable() {
     public void run() {
          while(!isStopped) {
              //perform listener event
              try {
                  //after every event sleep for a while
                  Thread.sleep(1000 *2)
              }
              catch(InterruptedException e){}
         }
     }
});

Теперь вы не будетеначать новый поток, пока предыдущий не остановился.

(Примечание: не уверен, что isAlive () является точным, вам может потребоваться создать собственную реализацию Thread, чтобы точно отразить, остановлен ли поток, если это не так)

0 голосов
/ 08 сентября 2011

Попробуйте сделать isStopped volatile, т.е. private static volatile boolean isStopped=false;. Может быть задержка синхронизации памяти между двумя потоками (основным и вашим).

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