1

나는 하나의 스레드가 매 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 객체를 만들고 다른 것들은 그대로 유지됩니다. 이게 옳은 거니?

스레드 안전성 문제가있는 경우이 문제를 해결하는 가장 좋은 방법은 무엇입니까? 여기

+0

아니요, 스레드로부터 안전하지 않습니다. 내가 발견 한 첫 번째 위반 사항 (더 이상 가지 않았다)은 모든 읽기가 공유 ArrayList를지도에서 가져 와서 섞는다는 것입니다. –

+0

이 질문은 자매 사이트 [코드 검토] (http://codereview.stackexchange.com/)에서보다 잘 맞는 것 같습니다. –

+0

@JBNizet 내 예제에서이 문제를 어떻게 해결할 수 있습니까? – user1234

답변

1

:

List<SocketInfo> liveSockets = liveSocketsByDc.get(entry.getKey()); 

당신의 다른 스레드가 잠재적으로 작성/병렬 같은 목록 개체를 읽고.

So : 스레드로부터 안전하지 않습니다. "외부"thread-safe 데이터 구조를 갖는 것은 도움이되지 않습니다. 그 thread-safe 물건이 thread-safe하지 않은 데이터를 포함하고있을 때; 그러나 동시에 "작업 한"!

+0

내 코드에서이 스레드 안전성 문제를 해결하는 가장 좋은 방법은 무엇입니까? – user1234

관련 문제