我有一些代码,我想知道在多线程环境中我是否会丢失数据......
以下是示例代码:
public class TestingJavaThreading {
private final Map> data = Maps.newConcurrentMap();
private final HttpClient client;
private final AsyncDataProvider provider;
private final String baseUrl;
// This method is called first...
public void init(String code) {
// We initialise the set to ensure it doesn't throw a null pointer exception or something weird...
data.put(code, Sets.newConcurrentHashSet());
// We tell the provider we're interested in data...
provider.subscribeToDataFrom(code);
// This HTTP call may take long time, and we can't afford losing data, that's why we subscribed beforehand in the previous line...
List elements = client.request(baseUrl + code);
// We add all of the new elements, meanwhile some elements may have been added by "onMessageFromProvider"
data.get(code).addAll(elements);
data.get(code)
.stream()
.map( /* some transformations here, whatever... */)
.forEach(e -> System.out.println(e));
// Now we've printed the merged data from "onMessageFromProvider" + the HTTP call
// We remove the element from the map, so now we only receive data from "onMessageFromProvider"
data.remove(code);
}
public void onMessageFromProvider(String code, String element) {
final Set newSet = data.computeIfPresent(code, (k, v) -> {
v.add(element);
return v;
});
if (newSet == null) {
// Do something else...
}
}
}
基本上,被调用的初始方法是init。步骤是这样的:
初始化CHM以确保其包含数据
我们有一个提供商,可以实时提供有关该元素的信息,但它不提供过去的数据。当数据来自提供者时,它调用方法“onMessageFromProvider”
为了获取项目的先前数据,我们需要进行单独的HTTP调用,然后将来自“onMessageFromProvider”的数据与来自HTTP调用的结果合并。完成之后,我们可以完全依赖“onMessageFromProvider”正在做的事情
一旦我们得到HTTP调用的结果,我们将它与来自“onMessageFromProvider”的数据合并,同时,我们应用转换,并打印生成的合并集
现在我们删除了地图密钥,因此我们可以完全依赖“onMessageFromProvider”正在做的事情
醇>
在步骤(3)运行时,这是否会导致数据丢失?我该如何解决?我应该在哪里放置更多代码,以尽可能少地依赖synchronished?
所以恢复,我的目标是永远不会丢失数据,我想确保我的算法100%保证。
对于loooong帖子感到抱歉,希望它有意义。
更新
根据输入,我用实际样本更新代码,目前看起来像这样:
public class Main {
public static void main(String[] args) throws InterruptedException {
new Main().init("X");
}
public void init(String code) throws InterruptedException {
subscribeToDataFrom(code);
CompletableFuture
.supplyAsync(getDataFromHttpRequest());
}
private Supplier> getDataFromHttpRequest() {
return () -> {
Set resultsToReturn = Sets.newHashSet();
try {
resultsToReturn.add("B");
resultsToReturn.add("C");
resultsToReturn.add("D");
resultsToReturn.add("E");
resultsToReturn.add("F");
Thread.sleep(1000); // Simulate it is a slow request...
} catch (Exception ex) {}
return resultsToReturn;
};
}
private void subscribeToDataFrom(String code) {
Runnable r = () -> {
while (true) {
onMessageFromProvider(code, UUID.randomUUID().toString());
}
};
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
}
public void onMessageFromProvider(String code, String element) {
// Here how do I create the completable future for usage in the previous CompletableFuture????
final Set newSet = data.computeIfPresent(code, (k, v) -> {
v.add(element);
return v;
});
if (newSet == null) {
System.out.println("Ok, now I can do something different with: " + element);
}
}
}