以下是我的启动后台线程的工厂代码TempScheduler
-
public class TempClientFactory {
public static IClient getInstance() {
new TempScheduler().startScheduler();
return ClientHolder.INSTANCE;
}
private static class ClientHolder {
private static final TempClient INSTANCE = new TempClient();
}
}
现在,客户将使用上述工厂通过上述工厂调用我们的代码。他们只会获得一次我们的Client实例,然后继续使用该实例来调用read
我的实现中的方法-
IClient client = TempClientFactory.getInstance();
String response = client.read(userId);
下面是我的后台线程代码,它将从URL获取数据,进行解析并将其存储在类变量中-
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, 10, TimeUnit.MINUTES);
}
}
// call the servers and get the data and then parse
// the response.
private void callServers() {
String url = "url";
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(url, String.class);
parseResponse(response);
}
// parse the response and store it in a variable
private void parseResponse(String response) {
//...
ConcurrentHashMap<String, Map<Integer, String>> primaryTables = null;
//...
// store the data in ClientData class variables which can be
// used by other threads
ClientData.setPrimaryMapping(primaryTables);
}
}
解析来自URL的数据后,我上面的后台线程将ClientData
通过使用其setter将结果存储在我的类的变量中。下面是我的ClientData class
。
public class ClientData {
private static final AtomicReference<Map<String, Map<Integer, String>>> primaryMapping = new AtomicReference<>();
public static Map<String, Map<Integer, String>> getPrimaryMapping() {
return primaryMapping.get();
}
public static void setPrimaryMapping(Map<String, Map<Integer, String>> map) {
primaryMapping.set(map);
}
}
问题陈述:-
现在有趣的部分到了,正如您所看到的,客户将使用上述工厂调用我们的代码,并在他们对getInstance()
方法进行调用后立即启动我的后台线程,该后台线程将从URL中获取数据,然后解析并将其存储在类变量中。但是getInstance()
执行该方法后,他们将read method
立即在我的客户代码中调用。
然后,我应该在实现代码中使用由后台线程设置的变量。我的实现代码具有read
方法的用途CallableTaks
,future.get
因此它将自动出现在call
下面的方法中。在下面的类中,我应该使用由我的后台线程设置的变量值。我需要使用getPrimaryMapping
method来获取下面的代码中的值。
public class ClientTask implements Callable<String> {
private String userId = null;
public ClientTask(String userId) {
this.userId = userId;
}
@Override
public String call() throws Exception {
//.....
String hostname = ClientData.getPrimaryMapping("some_string").get(some_number);
//....
}
}
这种方法的问题是,客户第一次调用我们的工厂来获取实例后,它将启动后台线程,该后台线程将从URL中获取数据并进行解析并将其存储在类变量中,但是它会立即调用read
我的实现类的方法。
现在可能第一次,我的后台线程仍在解析数据,但是实际的调用已经在里面了call method
,然后它将尝试从getPrimaryMapping
方法中获取数据,但将没有任何东西,对吧?为什么bcoz仍在解析数据。.因此,我如何确保在每次客户调用我们的代码时第一次进行解析,一旦解析完成,则只允许在call方法中获取变量值。
然后第二次就可以了。因为数据将存储在内存中,所以只有第一次才是问题。
有什么办法吗?
这不是一个很好的解决方案,但是CountDownLatch
可以解决这个问题:
public class ClientData {
private static final AtomicReference<Map<String, Map<Integer, String>>> primaryMapping = new AtomicReference<>();
private static final CountDownLatch firstSet = new CountDownLatch(1);
public static Map<String, Map<Integer, String>> getPrimaryMapping() {
try { firstSet.await(); } catch (Exception ignored) {}
return primaryMapping.get();
}
public static void setPrimaryMapping(Map<String, Map<Integer, String>> map) {
primaryMapping.set(map);
firstSet.countDown();
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句