Java 如何使用ScheduledExecutors只运行一次后台线程?

Java 如何使用ScheduledExecutors只运行一次后台线程?,java,multithreading,background-thread,scheduledexecutorservice,Java,Multithreading,Background Thread,Scheduledexecutorservice,下面是我的界面- public interface IClient { public String read(ClientInput input); } public class TempClient implements IClient { @Override public String read(ClientInput input) { } } 这是我的接口实现- public interface IClient { public String

下面是我的界面-

public interface IClient {
    public String read(ClientInput input);
}
public class TempClient implements IClient {

    @Override
    public String read(ClientInput input) {

    }
}
这是我的接口实现-

public interface IClient {
    public String read(ClientInput input);
}
public class TempClient implements IClient {

    @Override
    public String read(ClientInput input) {

    }
}
下面是我的工厂代码-

public class TempClientFactory {

    public static IClient getInstance() {
    new TempScheduler().startScheduler();
    return ClientHolder.INSTANCE;
    }

    private static class ClientHolder {
        private static final TempClient INSTANCE = new TempClient();
    }
}
现在我有了一个工厂,它获得了TempClient的实例,这样客户在调用我们的代码时就会使用下面的工厂

IClient client = TempClientFactory.getInstance();
client.read(input);
下面是我的背景线程代码-

public class TempScheduler {

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

        public void startScheduler() {
            final ScheduledFuture<?> taskHandle = scheduler.scheduleAtFixedRate(new Runnable() {
                public void run() {
                try {
                    callServers();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                }
            }, 0, 10L, TimeUnit.MINUTES);
        }
    }

    //... some code
}
公共类临时调度器{
private final ScheduledExecutorService scheduler=Executors.newScheduledThreadPool(1);
公共无效startScheduler(){
final ScheduledFuture taskHandle=scheduler.scheduleAtFixedRate(new Runnable()){
公开募捐{
试一试{
callServers();
}捕获(例外情况除外){
例如printStackTrace();
}
}
},0,10L,时间单位为分钟);
}
}
//... 一些代码
}
问题陈述:-

  • 现在我有一个后台线程,它将在 从URL获取数据、解析数据并存储数据的场景 在一个变量中。现在我想要的是我们的客户一开始 通过使用工厂调用使用我们的代码,我希望 背景线程开始。所以我决定打那个电话 我上面的
    TempClientFactory
    ,它工作得非常好
  • 现在这种方法的问题是,客户将继续呼叫我的TempClientFactory,所以它将始终启动后台线程。。我要寻找的是,如果后台线程启动一次,那么我不想从另一个线程再次启动它,但它应该在后台每10分钟继续运行一次,因为它已经第一次启动了


    如果我的理解是正确的,假设我只调用一次TempClientFactory,那么它将启动后台线程,并且我的后台线程将每10分钟继续运行一次。。如果我再次给我的工厂打电话,那么它会再次启动同样的后台,也会每10分钟运行一次?或者它将只启动一个后台线程,每10分钟运行一次?

    使用一个singleton方法,该方法将确保您拥有一个类的单个实例。要创建TempScheduler的对象,只需调用

     public class TempClientFactory {
    
        public static IClient getInstance() 
       {
    
           TempScheduler  obj=TempScheduler.getTempScheduler(); 
           if(obj.flag==false) 
           {
            obj.startScheduler();
           }
           return ClientHolder.INSTANCE;
        }
    
        private static class ClientHolder {
            private static final TempClient INSTANCE = new TempClient();
        }
    }
    
    
    
    
    
    
     public class TempScheduler {
    
                private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
                public static TempScheduler scheduler=null;
                public bool flag;
    
                    public void startScheduler() {
                        flag=true;
                        final ScheduledFuture<?> taskHandle = scheduler.scheduleAtFixedRate(new Runnable() {
                            public void run() {
                            try {
                                callServers();
                            } catch (Exception ex) {
                                ex.printStackTrace();
                            }
                            }
                        }, 0, 10L, TimeUnit.MINUTES);
                    }
                }
    
                private TempScheduler()
                {
    
                }
    
                synchronized public static TempScheduler getTempScheduler()
                {
                 if(scheduler==null)
                 {
                    scheduler=new TempScheduler();
                 }
                 return scheduler;
               }
    
    
                //... some code
            }
    
    公共类TempClientFactory{
    公共静态IClient getInstance()
    {
    TempScheduler obj=TempScheduler.getTempScheduler();
    如果(对象标志==假)
    {
    obj.startScheduler();
    }
    返回ClientHolder.INSTANCE;
    }
    私有静态类ClientHolder{
    私有静态最终TempClient实例=新TempClient();
    }
    }
    公共类临时调度器{
    private final ScheduledExecutorService scheduler=Executors.newScheduledThreadPool(1);
    publicstatictempscheduler=null;
    公共布尔旗;
    公共无效startScheduler(){
    flag=true;
    final ScheduledFuture taskHandle=scheduler.scheduleAtFixedRate(new Runnable()){
    公开募捐{
    试一试{
    callServers();
    }捕获(例外情况除外){
    例如printStackTrace();
    }
    }
    },0,10L,时间单位为分钟);
    }
    }
    专用临时调度器()
    {
    }
    同步的公共静态TempScheduler getTempScheduler()
    {
    if(调度程序==null)
    {
    调度器=新的临时调度器();
    }
    返回调度程序;
    }
    //... 一些代码
    }
    
    您需要手动防止再次调用它。您可以向内部类添加
    static

    public class TempClientFactory {
        public static IClient getInstance() {
            return ClientHolder.INSTANCE;
        }
    
        private static class ClientHolder {
            private static final TempClient INSTANCE = new TempClient();
    
            static {
                // You could do this here, as well, if it were more complicated
                //  than a one-line statement (e.g., requires try/catch):
                //INSTANCE = new TempClient();
    
                new TempScheduler().startScheduler();
            }
        }
    }
    
    与JVM为实例化singleton而保证的线程安全、延迟加载类似,它还将保证在此处启动调度程序的一次性访问

    因此,您将只启动并计划线程运行一次


    另外,我建议您转换
    ex.printStackTrace()转换为实际的日志语句。

    直接使用,而不是给它一个重复周期。如果您再次调用
    schedule
    ,或者当前调用它的同级调用,那么它将创建第二个线程。我只需要一个后台线程,它应该每10分钟运行一次。。我不想让客户继续打电话给我们,然后我的后台线程被调用。。。我还有别的办法吗?谢谢你的帮助
    ex.printStackTrace
    仅用于演示。。我的伐木工人在那边。。因此,如果我按照您建议的方式执行,它只会启动我的后台线程一次,如果有人再次致电我的工厂,那么它将不会再次启动后台线程。。正当而且,它也是线程安全的吗?正确。它是线程安全的,原因与singleton的实例化相同——JVM保证它使用内部类“
    static
    内容,而不锁定。它只会发生一次,你可以阅读更多关于它的内容。它与单例实例化有关,但是这个想法适用于我在这里所做的事情。