1

나는 ConcurrentHashMap과 그 맵에 String을 넣는 메소드를 가지고있다. 그런 다음 삽입 된 값을 기반으로 동기화 된 블록에서 몇 가지 작업을 수행한다. 키의 매핑이없는 경우ConcurrentHashMap putIfAbsent 初めて

putIfAbsent지정된 키에 관련 지을 수 있었던 이전의 값을 돌려줍니다 - 공식 문서에 따라이

putIfAbsent 반환 널 (null) 여부에 따라 실행되는이 개 조치는있다 아닙니다.

이제 여기에 속임수입니다. 첫 번째 작업 (putIfAbsent이 null을 반환하는 경우)이 먼저 실행되고 다른 모든 스레드가 보류되도록하려고합니다. 내 코드는 의도 한대로 작동합니다. 가끔 다른 스레드 login("some_id");에서 같은 문자열 값이 메소드를 호출하면

private final ConcurrentHashMap<String, String> logins = new ConcurrentHashMap<>(); 

public void login(String id){ 
     String inserted=logins.putIfAbsent(id,id); 

     synchronized(logins.get(id)){ 
      if(inserted==null){ 
       System.out.println("First login"); 
      }else{ 
       System.out.println("Second login"); 
      }   
     } 
} 

은 (시간의 5 %의 주위에) 나는 콘솔에서이 메시지 : 내가 변경해야 할 무엇

Second login 
First login 

항상 First login이 먼저 실행되도록 하시겠습니까?

업데이트 : 내가 읽은 바에 따르면 logins.get (id)가 null을 반환하므로 null 객체에서 동기화 할 수 있습니까?

+0

logins.putIfAbsent (id, id) 및 동기화 된 블록 명령문은 절대 아님. 그래서 두 번째 로그인이 먼저 실행되는 경우가 있습니다.또한 문자열 리터럴을 동기화하는 것은 좋지 않습니다. –

+0

'map'을'logins'해야합니까? –

+0

@MichaelEaster 예. 죄송합니다. 코드를 수정했습니다. –

답변

0
private final ConcurrentHashMap<String, String> logins= new ConcurrentHashMap<>(); 
private ConcurrentHashMap<String, Object> locks= new ConcurrentHashMap<>(); 


public void login(String id){ 

locks.putIfAbsent(id,new Object()); 
Object lock = locks.get(id); 
synchronized(lock) 
{ 
     String inserted=logins.putIfAbsent(id,id); 

      if(inserted==null){ 
       System.out.println("First login"); 
      }else{ 
       System.out.println("Second login"); 
      }   

} 
} 

참고 : 또한 ID가

을 삭제하거나 코드를

0

가끔 동기화 (떨어져 문자열 ID)에서 다른 필드를 사용하면 당신이 HashMaps을에서 항목을 제거되었는지 확인 (시간의 약 5 %) 콘솔에서이 메시지가 나타납니다.

추가 할 첫 번째 경쟁 조건이 있습니다.

이 경우 병목 현상은 System.out을 사용하는 것입니다. 이는 맵을 사용하는 것보다 동시 사용 또는 다른 방법을 사용하는 것보다 비용이 많이 드는 콘텐츠 리소스입니다. 당신은 단지 당신이 어쨌든

// use System.out as lock so logging of actions is always in order. 
private final Set<String> ids = Collections.newSetFromMap(new HashMap<>()); 

public void login(String id) { 
    synchronized (System.out) { 
     System.out.println(ids.add(id) ? "First login" : "Second login")l 
    } 
} 
0

자바 더 세분화을 제공하는 다른 동기화 메커니즘을 제공 얻어야 System.out에 잠금 장치가 하나의 잠금을 획득되도록

하는 경우, 당신은뿐만 아니라 당신의 코드를 단순화 할 수있다 , 그리고 IMO, 선명도.

아래 코드를 고려하십시오. 이 코드는 (a) 여러 작업을 잠금 장치로 보호하는 방법 (b) thenelse 섹션을 다르게 처리 할 수있는 방법을 보여줍니다 (예 : then은 잠금 기능을 사용하여 기능을 보호 함). 상황) :

class Task implements Runnable { 
    private String id; 
    private ConcurrentHashMap<String,String> logins; 
    private Lock lock; 

    public Task(String id, ConcurrentHashMap<String,String> logins, Lock lock) { 
     this.id = id; 
     this.logins = logins; 
     this.lock = lock; 
    } 

    public void run() { 
     login(id); 
    } 

    public void login(String id){ 
     lock.lock(); 

     String inserted = logins.putIfAbsent(id,id); 

     if (inserted==null) { 
      System.out.print("First login "); 
      // other functions that require synchronization 
      lock.unlock(); 
     } else { 
      lock.unlock(); 
      // functions that do NOT require synchronization 
      System.out.print("Second login "); 
     }   
    } 
} 
관련 문제