2011-09-08 129 views
2

我有一個守護程序線程,它在打開頁面時啓動。當頁面關閉時,線程停止。所以,在我的課持有線程,我有這樣的創建:如何停止運行多個實例的同一線程

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

+0

嘗試呼叫'了Thread.interrupt()'方法。 – Salw

+0

我已經嘗試過了 - 在我的問題中也提到了它。 – Bitmap

+0

'執行監聽事件'是做什麼的?它是否以某種方式檢查事件對象的存在?如果是這樣,使用wait/notify會不會更高效? –

回答

2

從@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); 
0

嘗試使isStopped volatile,即private static volatile boolean isStopped=false;。這兩個線程(主要和你自己)之間的內存同步可能存在滯後。

+0

'@Bart van Heukelom' isStopped已經不穩定,請參閱編輯。 – Bitmap

2

您可能會覆蓋isStopped的值false之前舊線程有機會看到它應該停止。問題就在這裏:

if(isStopped) 
{ 
    isStopped=false; 
} 

你應該更好地隔離代碼:爲每個線程創建的A單獨的實例,使isStopped一個實例volatile場(不static)。並刪除該代碼塊...

1

如果您的標誌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){} 
} 

通過設置標誌,它停止執行,但線程繼續檢查。

1

嘗試使用AtomicBoolean而不是布爾字段。 使用compareAndSet方法;讓我知道如果你需要更多的澄清,因爲javadoc是非常有用的。

0

將您的實例化移動到您的方法之外並使其變爲靜態。這個保證人的,你只會有這個線程的一個實例。

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

現在你不會,直到前一個已停止啓動一個新的線程:

private static Thread listener; 

給你方法一旦做到這一點,你可以添加此。

(NB,如果沒有把握的IsAlive()是正確的,則可能需要創建自己的線程中執行,以準確反映如果線程停止,如果它不是)

0

我會用一個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

'@Laurent Legrand' - 我知道這一點,我決定按個人原因去做。 thankx – Bitmap

相關問題