Singleton与Java多线程应用程序



简单地说,我想点击按钮来运行后台任务(分离的线程)。我面临两个问题:

  • 如果用户多次点击按钮===>许多线程将创建
  • 即使我使用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();

我尝试了同步方法,但没有成功,任何提议都是受欢迎的。

我建议您使用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()停止服务。

即使只有一个RunnableCheck实例,您的start方法也不能保证只创建一个"我的任务"线程:因为线程引用和后续赋值的检查不是原子的,如果两个线程碰巧同时将t == null求值为true(或者,至少,第二个线程可以在第一个线程能够将非null值分配给t之前将其求值为true),则可以创建并启动两个线程。

您可以通过以下方式进行防护:

  • 使start方法同步,因此多个线程不能同时运行该方法
  • 添加一个AtomicBoolean来记录线程是否已创建/启动。通过原子更新该标志的值,两个线程不可能将其设置为true,因此不可能创建和启动两个新的Thread

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

当用户单击多次时,您希望事件发生多次还是只发生一次?如果多次,您不希望使用singleton,而是希望创建一个工作队列。

您可以通过以下两种方式之一来实现这一点,第一种是使用一个想要一个线程池,很可能是使用ExecutorService中的一个。

第二种选择是让一个队列从队列中读取,让一个线程从队列中进行读取。

如果您希望事件只发生一次,那么您需要禁用该按钮,直到它完成,使启动同步,以便一次只有一个线程可以调用它,然后在线程完成后将t设置为null(即run()中的最后一项)。

相关内容

  • 没有找到相关文章

最新更新