简体   繁体   English

具有Java多线程应用程序的Singleton

[英]Singleton with Java multithreading app

Briefly, I want to click on a button to run a background task (separated thread). 简要地说,我想单击一个按钮以运行后台任务(独立线程)。 I faced two problems: 我面临两个问题:

  • What if user click many times on that button ==>Many thread will be created. 如果用户多次单击该按钮 ==>将会创建许多线程,该怎么办?
  • Even if I use Singleton mechanism, I face another problem which is the fact that only one time that instance will be created even though after task accomplishes, user can't anymore re-run the process (second click on the button ). 即使我使用Singleton机制,我也面临另一个问题,即即使在任务完成后,仅一次创建该实例的事实,用户也无法再次运行该过程(第二次单击按钮 )。

My class: 我的课:

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

In the caller class: 在呼叫者类别中:

RunnableCheckFeeders.getDefault().start();

I tried with Synchronized methods but in vain, any proposition is welcome. 我尝试了同步方法,但是徒劳的任何主张都是徒劳的。

Your start method doesn't guarantee that only one "my task" thread will be created, even if there is only one instance of RunnableCheck : because the checking of the thread reference and subsequent assignment is not atomic, it is possible for two threads to be created and started if both happen to evaluate t == null to true at the same time (or, at least, a second thread can evaluate it to true before the first thread was able to assign a non-null value to t ). 即使只有一个RunnableCheck实例,您的start方法也不能保证将仅创建一个“我的任务”线程:因为线程引用的检查和后续分配不是原子的,所以两个线程有​​可能如果两者都同时将t == null评估为true(或者至少第二个线程可以在第一个线程能够为t分配非null值之前将其评估为true),则创建并开始创建。

You can guard for this by: 您可以通过以下方式对此进行防范:

  • Making the start method synchronized, so multiple threads cannot run the method at the same time; 使start方法同步,以便多个线程无法同时运行该方法;
  • Add an AtomicBoolean to record if the thread has been created/started. 添加一个AtomicBoolean来记录是否已创建/启动线程。 By updating the value of this flag atomically, it is not possible for two threads to set it to true , and thus impossible for two new Thread s to be created and started: 通过自动更新此标志的值,两个线程不可能将其设置为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(); } 

I suggest you use an ExecutorService. 我建议您使用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);
      }
 }

This will submit a new task only if there is not already one running. 仅当尚未运行一项新任务时,它才会提交新任务。 It won't create more than one thread but you can submit tasks after a previous one finishes. 它不会创建多个线程,但是您可以在上一个线程完成后提交任务。 You can call service.shutdown() to stop the service. 您可以调用service.shutdown()停止服务。

When a user clicks multiple times then do you want the event to happen multiple times, or just the once? 当用户单击多次时,您是否希望事件发生多次或仅发生一次? If multiple times, you don't want a singleton, but rather to create a queue of work. 如果多次,您不希望单身,而是创建工作队列。

You can do this in one of two ways, the first is to use aa want a thread pool, likely using one from the ExecutorService . 您可以通过以下两种方式之一执行此操作,第一种是使用想要的线程池,可能使用ExecutorService中的一种

Your second option is to have a single queue reading from a queue and a single thread reading from the queue. 你的第二个选择是有一个单一的队列从读取队列 ,并从队列中一个单独的线程读取。

If you want the event to only happen the once then you need to disable the button until it is completed, make start synchronized so only one thread can call it at a time and then set t to null once the thread finishes (ie the last item in run() ). 如果您希望事件仅发生一次,则需要禁用该按钮,直到它完成为止,使启动同步,这样一次只能有一个线程可以调用它,一旦线程结束(即最后一个项目),则将t设置为nullrun() )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM