2015-11-25 60 views
0

簡而言之,我想單擊一個按鈕來運行後臺任務(單獨的線程)。我面臨兩個問題:Singleton with Java multithreading app

  • 如果什麼用戶點擊上按鈕多次 ==>多線程將被 創建。
  • 即使我使用Singleton機制,我面臨的另一個問題是,即使任務完成後只有一次該實例將被創建,但用戶不能再重新運行該進程(第二次單擊按鈕)。

我的類:

package mypack.check; 

public class RunnableCheck implements Runnable { 

    private Thread t; 
    private static RunnableCheckFeeders instance; 

    public RunnableCheckFeeders getDefault() { 
     if (instance == null) { 
      instance = new RunnableCheckFeeders(); 
     } 
     return instance; 
    } 

    @Override 
    public void run() { 
     //What the thread is supposed to do... 
    } 

    public void start() { 
     if (t == null) { 
      t = new Thread(this, "My task"); 
      t.start(); 
     } 
    } 
} 

在主叫類:

RunnableCheckFeeders.getDefault().start(); 

我試圖與同步的方法,但徒勞的,任何命題是值得歡迎的。

+1

在線程完成加載之前,您不能禁用該按鈕嗎?在這種情況下,Java的'Future '可能很有用:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html。如果線程完成,您可以檢查'Future '。 –

+2

因爲'getDefault'不是靜態的,所以你需要創建'RunnableCheck'實例來調用'getDefault'來獲取靜態實例。因此,'RunnableCheckFeeders.getDefault()'甚至不能編譯。 –

+0

單擊按鈕時是否創建RunnableCheck的新實例? –

回答

1

我建議你使用一個ExecutorService。

enum RunOne {; // no instances 
     static final ExecutorService service = Executors.newSingleThreadedExecutor(); 
     static Future last = null; 

     static synchronized void run(Runnable run) { 
      if (last != null && !last.isDone()) return; 
      last = service.submit(run); 
     } 
} 

只有在尚未運行的情況下,纔會提交新的任務。它不會創建多個線程,但您可以在完成上一個任務後提交任務。您可以撥打service.shutdown()停止服務。

0

當用戶多次點擊時,你想讓事件多次發生,還是隻發生一次?如果多次,你不想要一個單身人士,而是創建一個工作隊列。

您可以通過以下兩種方法之一來做到這一點,第一種方法是使用a想要一個線程池,可能使用ExecutorService中的一個。

您的第二個選擇是從queue中讀取單個隊列,並從隊列讀取單個線程。

如果你希望事件只發生一次,那麼你需要,直到完成了將禁用按鈕,使啓動同步,所以只有一個線程可以同時調用它,然後設置tnull一旦線程完成(即run()中的最後一項)。

1

start方法並不能保證只有一個「我的任務」的線程將被創建,即使是RunnableCheck只有一個實例:因爲線程參考,並隨後指派的檢查是不是原子,可以對於兩個線程的創建和啓動,如果兩者碰巧同時將t == null評估爲true(或者至少第二個線程可以在第一個線程能夠將非空值分配給t之前將其評估爲真) 。

您可以通過守護這個:

  • 使得start方法同步,所以多個線程不能運行在同一時間的方法;
  • 添加AtomicBoolean來記錄線程是否已創建/啓動。通過更新該標誌原子的價值,這是不可能的兩個線程將其設置爲true,因而不可能要創建兩個新的Thread S和啓動:

    private final AtomicBoolean started = new AtomicBoolean(); 
    private Thread t; 
    
    public void start() { 
        if (!started.compareAndSet(false, true)) { 
        return; 
        } 
    
        t = new Thread(this, "My task"); 
        t.start(); 
    }