나는 하나의 스레드가 매 30 초마다 업데이트 한 ConcurrentHashMap
클래스를 가지고 있으며 getNextSocket()
메서드를 호출하여 동일한 ConcurrentHashMap
에서 읽는 다중 판독기 스레드를 읽었습니다.단일 스레드에서 ConcurrentHashMap을 채운 다음 경쟁 조건없이 여러 스레드에서 읽을 수 있습니까?
다음은 초기화시 ConcurrentHashMap
을 채우는 데 connectToSockets()
메서드를 호출하고 updateSockets()
메서드를 호출하여 매 30 초마다 같은지도를 업데이트하는 백그라운드 스레드를 시작하는 내 싱글 톤 클래스입니다.
그리고 여러 스레드에서 정보를 얻기 위해 동일한 맵을 사용하는 다음 사용 가능한 라이브 소켓을 얻으려면 getNextSocket()
메서드를 호출합니다. 나 또한 SocketInfo
클래스가 불변인지 여부에 상관없이 모든 소켓의 상태를 포함하고 있습니다.
public class SocketHolder {
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private final Map<DatacenterEnum, List<SocketInfo>> liveSocketsByDc = new ConcurrentHashMap<>();
// Lazy Loaded Singleton Pattern
private static class Holder {
private static final SocketHolder INSTANCE = new SocketHolder();
}
public static SocketHolder getInstance() {
return Holder.INSTANCE;
}
private SocketHolder() {
connectToSockets();
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
updateSockets();
}
}, 30, 30, TimeUnit.SECONDS);
}
private void connectToSockets() {
Map<DatacenterEnum, ImmutableList<String>> socketsByDc = TestUtils.SERVERS;
for (Map.Entry<DatacenterEnum, ImmutableList<String>> entry : socketsByDc.entrySet()) {
List<SocketInfo> addedColoSockets = connect(entry.getKey(), entry.getValue(), ZMQ.PUSH);
liveSocketsByDc.put(entry.getKey(), addedColoSockets);
}
}
private List<SocketInfo> connect(DatacenterEnum dc, List<String> addresses, int socketType) {
List<SocketInfo> socketList = new ArrayList<>();
// ... some code here
return socketList;
}
// called from multiple reader threads to get next live available socket
public Optional<SocketInfo> getNextSocket() {
Optional<SocketInfo> liveSocket = getLiveSocket(liveSocketsByDc.get(DatacenterEnum.CORP));
return liveSocket;
}
private Optional<SocketInfo> getLiveSocket(final List<SocketInfo> listOfEndPoints) {
if (!CollectionUtils.isEmpty(listOfEndPoints)) {
Collections.shuffle(listOfEndPoints);
for (SocketInfo obj : listOfEndPoints) {
if (obj.isLive()) {
return Optional.of(obj);
}
}
}
return Optional.absent();
}
// update CHM map every 30 seconds
private void updateSockets() {
Map<DatacenterEnum, ImmutableList<String>> socketsByDc = TestUtils.SERVERS;
for (Entry<DatacenterEnum, ImmutableList<String>> entry : socketsByDc.entrySet()) {
List<SocketInfo> liveSockets = liveSocketsByDc.get(entry.getKey());
List<SocketInfo> liveUpdatedSockets = new ArrayList<>();
for (SocketInfo liveSocket : liveSockets) {
Socket socket = liveSocket.getSocket();
String endpoint = liveSocket.getEndpoint();
boolean sent = ....;
boolean isLive = sent ? true : false;
// is this right here? or will it cause any race condition?
SocketInfo state = new SocketInfo(socket, liveSocket.getContext(), endpoint, isLive);
liveUpdatedSockets.add(state);
}
// update map with new liveUpdatedSockets
liveSocketsByDc.put(entry.getKey(), liveUpdatedSockets);
}
}
}
질문 :
내 위의 코드 스레드 안전하고 updateSockets()
및 getNextSocket()
방법에는 경쟁 조건이 없다? 내 updateSockets()
방법에서
, 이미 updateSockets()
방법으로 초기화 또는 30 초 다음 간격 동안 connectToSockets()
방법으로 이전에 채워진 liveSocketsByDc
ConcurrentHashMap의에서 List<SocketInfo>
추출한 다음 나는 동일한 목록 liveSockets
을 반복 오전에 따라 새로운 SocketInfo
객체를 생성 isLive
이 true 또는 false인지 여부 그리고 나서 liveSocketsByDc
ConcurrentHashMap을이 새로운 SocketInfo
개체로 업데이트합니다. 이 모양이 맞습니까? 다중 판독기 스레드 때문에 나는 getNextSocket()
메서드 호출을 호출하려고합니다. getLiveSocket
같은 맵을 사용하는 메서드는 다음 사용 가능한 라이브 소켓을 가져옵니다.
나는 liveSockets
목록을 작성한 다음 isLive
필드를 변경하여 새 SocketInfo
객체를 만들고 다른 것들은 그대로 유지됩니다. 이게 옳은 거니?
스레드 안전성 문제가있는 경우이 문제를 해결하는 가장 좋은 방법은 무엇입니까? 여기
아니요, 스레드로부터 안전하지 않습니다. 내가 발견 한 첫 번째 위반 사항 (더 이상 가지 않았다)은 모든 읽기가 공유 ArrayList를지도에서 가져 와서 섞는다는 것입니다. –
이 질문은 자매 사이트 [코드 검토] (http://codereview.stackexchange.com/)에서보다 잘 맞는 것 같습니다. –
@JBNizet 내 예제에서이 문제를 어떻게 해결할 수 있습니까? – user1234