![](/img/trans.png)
[英]How do I make this Java code operate properly? [Multi-threaded, race condition]
[英]Java code race condition multi-threaded?
我有一些代碼,我想知道在多線程環境中是否會丟失數據...
這是示例代碼:
public class TestingJavaThreading {
private final Map<String, Set<String>> 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<String> 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<String> newSet = data.computeIfPresent(code, (k, v) -> {
v.add(element);
return v;
});
if (newSet == null) {
// Do something else...
}
}
}
基本上,被調用的初始方法是init
。 步驟如下:
在運行步驟(3)時,是否可能導致數據丟失? 我該如何解決? 我應該在哪里放置更多代碼,以便盡可能少地依賴於synchronished
?
因此,繼續進行下去,我的目標是永不丟失數據,並且我想確保我的算法能夠100%保證。
很抱歉,您的長期評價是有道理的。
UPDATE
基於輸入,我將使用一個真實的示例更新代碼,當前看起來像這樣:
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<Set<String>> getDataFromHttpRequest() {
return () -> {
Set<String> 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<String> 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);
}
}
}
CompletableFuture類,具有組合和執行差異任務的方法
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html :
例如 :
CompletableFuture<String> httpTask = CompletableFuture.supplyAsync(
() -> new HttpTask(httpClient));
Set<String> result = httpTask.thenApply(elements -> //onMessageProvider method
// maybe you can create a Callable class with the logic)
.thenApply(mergedElements -> //remove code).get();
//or try another method
class HttpTask extends Callable<List<String>>{
private HttpClient client;
public HttpTask(HttpClient client){
this.client = client;
}
@Override
public List<String> call() throws Exception {
return client.httpCall(...);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.