2017-04-02 11 views
0

add 메서드가 여러 스레드에서 호출되어 clientidToTimestampHolder LinkedBlockingQueue를 채우는 클래스가 있습니다. 그리고 나서 같은 클래스에서 나는 매 30 밀리 초마다 실행되는 백그라운드 스레드를 가지고 processData() 메서드를 호출하여 clientidToTimestampHolder을 Map List에 배수 한 다음 적절한 메서드를 호출하여 다른 서비스에 데이터를 보내도록 List를 반복합니다.여러 스레드에서 메서드를 호출하여 데이터 구조를 채운 다음 단일 백그라운드 스레드에서 해당 데이터 구조를 읽을 수 있습니까?

타임 스탬프가 같은 여러 사용자 ID를 여러 번 얻을 수 있으므로 맵과 함께 LinkedBlockingQueue을 사용하고 있습니다.

public class Handler { 
    private final ScheduledExecutorService executorService = Executors 
     .newSingleThreadScheduledExecutor(); 
    private final LinkedBlockingQueue<Map.Entry<String, Long>> clientidToTimestampHolder = 
     new LinkedBlockingQueue<>(); 

    private static class Holder { 
    private static final Handler INSTANCE = new Handler(); 
    } 

    public static Handler getInstance() { 
    return Holder.INSTANCE; 
    } 

    private Handler() { 
    executorService.scheduleAtFixedRate(new Runnable() { 
     @Override 
     public void run() { 
     processData(); 
     } 
    }, 0, 30, TimeUnit.MILLISECONDS); 
    } 

    // called by multiple threads to populate clientidToTimestampHolder map 
    public void add(final String clientid, final Long timestamp) { 
    clientidToTimestampHolder.offer(Maps.immutableEntry(clientid, timestamp)); 
    } 

    // called by single background thread every 30 milliseconds 
    public void processData() { 
    final List<Map.Entry<String, Long>> entries = new ArrayList<>(); 
    clientidToTimestampHolder.drainTo(entries); 
    for (Map.Entry<String, Long> entry : entries) { 
     String clientid = entry.getKey(); 
     long timestamp = entry.getValue(); 
     boolean isUpdated = isUpdatedClient(clientid, timestamp); 
     if (!isUpdated) { 
     updateClient(String.valueOf(clientid)); 
     } 
    } 
    } 
} 

내 위의 코드 스레드 안전한가요 거기에는 경쟁 조건이없는 내가 processData() 방법으로 데이터를 놓치지 않을 것입니다? add 메서드는 여러 스레드에서 호출되고 난 다음 LinkedBlockingQueue에서 데이터를 추출하는 processData() 메서드를 호출하기 위해 매 30 밀리 초마다 실행되는 단일 배경 스레드가 있습니다.

답변

1

익명 클래스에는 외부 클래스에 대한 참조 (예 : Handler)가 포함되어 있습니다 (익명 클래스는 this). 마지막 필드가 고정되기 전에 안전하지 않게 this 참조를 게시 했으므로 실행 프로그램의 스레드는 읽을 때 올바르게 초기화 된 컬렉션을 볼 수 없습니다.

그 외에도 나는 processData이 업데이트를 놓치게되는 것을 보지 못했습니다. 드레인 작업이 동시 쓰기를 포착하지 못하면 다음 실행시에는 수행되지 않습니다. 이 경우 (당신은 잠글 필요가 있습니다) 걱정하지 않는 한, 컬렉션을 수정하지 않는 한 괜찮아 보입니다.

문자열에서 String#valueOf의 목적은 무엇입니까?

+0

나는이 참고 문헌을 부적절하게 출판 했습니까? 어떻게 해결할 수 있을까요? 그래'String # valueOf' 내가 고칠거야. – user1234

+0

생성자입니다. 안전하지 않은 게시를 방지하는 일반적인 방법은 정적 팩토리를 사용하고 생성 한 후에 예약 된 작업을 시작하는 것입니다. 즉, 'Handler newInstance() {Handler h = new Handler(); h.executorService.scheduleAtFixedRate (...); 귀환 h; }'를 호출하고 INSTANCE 홀더를 초기화하기 위해 팩토리를 사용하십시오. – xTrollxDudex