开发者

How to stop the same thread from running multiple instances

开发者 https://www.devze.com 2023-04-04 01:35 出处:网络
I have a daemon thread which is started when a page is opened. The thread is then stopped when the page is closed. So in my class which holds the thread, I have it created like this:

I have a daemon thread which is started when a page is opened. The thread is then stopped when the page is closed. So in my class which holds the thread, I have it created like this:

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;
  }
}

Upon investigation, I have noticed that when the page is closed and not opened again within say 30 seconds interval, the thread is gracefully stopped.

But when the page is closed and re-opened within say 2 seconds interval the old thread does not get stopped and hence runs simultaneously with a new one.

And so as you can see from below image, I have the same thread started again w开发者_StackOverflow社区hen I close and quickly open the page.

Do anyone knows how to prevent this from occurring?

I have tried using thread interrupt where I reset the mutex but no joy.

EDITED:

isStopped is volatile.

How to stop the same thread from running multiple instances


To follow on from @Jordão's answer, the isStopped variable should be per thread. I would recommend using something like an AtomicBoolean and changing your thread code to be approximately:

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;
}

Then back in your page controller you can do:

AtomicBoolean isStopped = testListener();
// do the page stuff
...
// when done stop the thread
isStopped.set(true);


You're probably overriding the value of isStopped with false before the old thread has a chance to see that it should stop. The problem is here:

if(isStopped) 
{
  isStopped=false;  
}

You should better isolate your code: create separate instances of A for each thread and make isStopped an instance volatile field (not static). And remove that block of code...


If your flag isStopped is not true for at least 2 seconds, your thread could be sleeping when this happens. A much simpler solution is to avoid start/stopping the thread as this could cause as much overhead as it saves (it certainly complicates the issue)

This is what I would do is start the thread once and only once.

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){}
}

By setting the flag, it stops performing, but the thread keeps checking.


Try using AtomicBoolean instead of the Boolean field. Use the compareAndSet method; let me know if u need more clarification as the javadocs are quite useful.


Try making isStopped volatile, i.e. private static volatile boolean isStopped=false;. There may be a lag in memory synchronization between the two threads (the main one and your own).


Move your instantiation outside of your method and make it static. This guarentee's you will only ever have one instance of this Thread.

private static Thread listener;

Once this is done you can add this to you're method:

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){}
         }
     }
});

Now you won't start a new thread until the previous one has stopped.

(NB, not sure if isAlive() is accurate, you may need to create your own Thread implementation to accurately reflect if the thread is stopped if it isn't)


I would used a java.util.concurrent.ScheduledExecutorService for that. It will manage the thread and the scheduling of the task.

For instance:

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号