gpt4 book ai didi

java - 如何高效地读取多线程程序中的共享数据?

转载 作者:行者123 更新时间:2023-12-01 18:37:50 24 4
gpt4 key购买 nike

我有一个后台线程正在更新我的类变量之一。我正在使用每 10 分钟运行一次的 ScheduledExecutorService 。下面是我的后台线程代码 -

我的下面的类所做的是,它将每 10 分钟运行一次并解析来自 URL 的数据并将其存储在变量中。

public class ScheduledCall {

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

public void startScheduleTask() {

final ScheduledFuture<?> taskHandle = scheduler.scheduleAtFixedRate(
new Runnable() {
public void run() {
try {
callServers();
} catch(Exception ex) {
ex.printStackTrace(); //or loggger would be better
}
}
}, 0, 10, TimeUnit.MINUTES);
}

private void callServers() {
String url = "url";
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(url, String.class);
parseResponse(response);

}

private void parseResponse(String response) {
//...
ConcurrentHashMap<String, Map<Integer, String>> primaryTables = null;

//...

// store the data in ClientData variables which can be
// used by other threads
ClientData.setHostToNodesTable(primaryTables);

}
}

解析来自 URL 的数据后,它将使用其 setter 将结果存储在我的类 ClientData 的变量中。下面是我的 ClientData 类

public class ClientData {

private static ConcurrentMap<String, Map<Integer, String>> hostToNodesTable = null;

// setters and getters here

}

现在有趣的部分来了。我有一个单独的多线程程序,它与上述后台线程代码在同一应用程序中运行。并且该多线程程序必须访问上述字段。我在下面的多线程程序中使用 Future 和 Callable 任务,该程序尝试从其 getter 访问 hostToNodesTable 值 -

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.getHostToNodesTable("some_string").get(some_number);

//....

}
}

现在我知道这不是线程安全的,因为当后台线程更新 map 时,我的另一个线程正在尝试从中检索值,这可能是可能的。如何确保该线程安全?还有其他我应该知道的问题吗?

最佳答案

恕我直言,一个简单的解决方案是使用 AtomicReference。

private static final AtomicReference<Map<String, Map<Integer, String>>> hostToNodesTable 
= new AtomicReference<>();

static Map<String, Map<Integer, String>> getTable() {
return hostToNodesTable.get();
}


static void setTable(Map<String, Map<Integer, String>> map) {
hostToNodesTable.set(map);
}

这样你的后台线程就永远不会改变表。它只是创建一个新的 HashMap,构建它,完成后替换整个内容。

对于读者来说,他们可以调用 getTable() 并根据需要使用 map ,但在再次调用 getTable() 之前不会看到任何更改。

由于您无论如何都要替换整个映射(无需删除条目),因此这比使用 ConcurrentHashMap 效率更高。

<小时/>

正如 Holger 指出的,这只是包装了一个 volatile 引用,一个更简单的解决方案是仅使用这样一个 volatile 字段。如果这样做,您必须记住获取本地副本(将其分配给本地变量),这样您多次引用它,它在使用时就不会改变。

关于java - 如何高效地读取多线程程序中的共享数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21109685/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com