仅在未执行或之前未启动或仅创建一个线程实例的情况下,如何启动线程

时间:2019-04-12 06:37:39

标签: java multithreading thread-safety

我有以下方法,每当我单击一个按钮时都会调用此方法,结果是在按下按钮时一次又一次地启动新线程,这导致线程的多次初始化,但是我只希望一个线程应该得到执行,我怎么能做到这一点。

    private void scheduleMessages() {
    new Thread(new Runnable() {
        @Override
        public void run() {
         //Some operations
        }
    }).start();
}

注意:这是一个很小的方法,我不想创建一个单独的类,只是为了使其成为单例,因此不使用单例模式的解决方案将不胜感激。

3 个答案:

答案 0 :(得分:1)

如果无法通过实例检查isActive(),则应创建一个信号量变量-一个布尔值,在启动线程时将其设置为true,在启动线程时将其设置为false完成。

private void scheduleMessages() {
    if (!taskRunning){
        new Thread(new Runnable() {
            @Override
            public void run() {
               taskRunning = true;
               //Some operations
               taskRunning = false;
            }
        }).start();
    }
}

答案 1 :(得分:0)

将该线程设为后台线程-也许在第一次按下该按钮时将其初始化。

让该线程侦听队列-并对该队列中的消息进行操作。

每当再次按下该按钮时,就将新消息放入队列。

答案 2 :(得分:0)

如果需要在特定数量的线程上执行每个请求,则可以使用线程池,让执行者管理队列。

private ExecutorService services;
private final static int POOL_SIZE = 1;

public MessagesService(){
    services = Executors.newFixedThreadPool(POOL_SIZE);
}

public void scheduleMessages(Runnable r){
    services.submit(r);
}

如果您调用addCall x次,则x线程将在最后执行,但使用的线程数绝不能超过池中可用的线程数。这里有1个线程。


对于仅接受一个请求的系统,您可以使用相同的方法,但要检查单个线程执行器返回的Future。这样,您可以检查服务的状态。

private ExecutorService services;
private Future<?> lastCall; 

public MessagesService() {
    services = Executors.newSingleThreadExecutor();
    lastCall = null;
}

public synchronized void scheduleMessages(Runnable r) {
    if(!isScheduled()){
        lastCall = services.submit(r);
    }
}

public boolean isScheduled(){
    return lastCall != null && !lastCall.isDone();
}

这样,Runnable不需要更新标志,从而提供了可重用的解决方案。

这里是Runnable的示例,用于测试这些代码:

new Runnable() { 
    System.out.println("Running");
    try {
       Thread.sleep(500);
    } catch (Exception e) {
        e.printStackTrace();
    }
}