[英]Singleton with Java multithreading app
Briefly, I want to click on a button to run a background task (separated thread). 简要地说,我想单击一个按钮以运行后台任务(独立线程)。 I faced two problems:
我面临两个问题:
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: 您可以通过以下方式对此进行防范:
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
设置为null
在run()
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.