2015-11-25 32 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(); 
    }