2012-06-15 3 views
0

좋은 날,Java의 LinkedList 클래스와의 동시성

Java의 LinkedList에 동시성 문제가 있습니다. "Listener"라는 "MessageHandlers"의 LinkedList 멤버 변수를 가진 "Connection"이라는 Object 유형이 있습니다. 그런 다음 두 개의 다른 스레드가 있습니다. 하나는 수정하고 하나는 동일한 LinkedList를 반복하는 것입니다.

sychronized 코드 블록을 사용하도록 제안하는 많은 다른 StackOverflow 관련 질문을 보았지만이 모든 것이 도움이되지는 않습니다. LinkedList를 동시 연결 목록으로 만들려고했지만 아직 수신 중입니다.

Exception in thread "Thread-1" java.util.ConcurrentModificationException 

예외입니다. 누구든지 시도 할 다른 제안이 있습니까? 여기 내 코드의 일부 snipbits입니다 ...

public synchronized Object ReadObject() throws java.io.IOException 
{ 
    Object obj = null; 

    try 
    { 
     obj = input.readObject(); 

     synchronized(listeners) 
     { 
      Iterator<MessageHandler> i = listeners.iterator(); 

      while(i.hasNext()) 
      { 
       i.next().MessageReceived(obj, this); 
      } 
     } 
    } 
    catch (IOException e) 
    { 
     e.printStackTrace(); 
     throw e; 
    } 
    catch (ClassNotFoundException e) 
    { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    return obj; 
} 

위의 코드는 내 연결 개체 안에 있습니다. 소켓으로부터 데이터를 읽어들이는 소켓의 ObjectInputStream를 가지는 함수로부터 불려갑니다. "input"는 ObjectInputStream의 인스턴스입니다.

public void addNewLoggedInUser(User user) throws Exception 
{ 
    for(User u:loggedInUsers) 
    { 
     if(u == user) 
     { 
      throw new Exception("That user is already logged in"); 
     } 
    } 

    //Add the new users 
    loggedInUsers.add(user); 

    synchronized(user.getConnection().getListeners()) 
    { 
     user.getConnection().getListeners().add(this); 
    } 

    this.SendGameStatusUpdateToAllLoggedinPlayers(); 
} 

나는 그 방법 user.getConnection()를 호출. getListeners을(). (이)을 추가하여 예외를 얻고있다.

이것은 연결 클래스의 생성자입니다. 고지 그는 Collections.synchronizedList

어떤 아이디어? 당신의 도움을 주셔서 대단히 감사합니다!

+0

동기화 된 블록 매개 변수의 user.getConnection(). getListeners() 인스턴스와 리스너가 동일한 인스턴스입니까? – George

+0

반복되는 동안 목록을 변경 (추가/제거 된 요소)하면 ['ConcurrentModificationException'] (http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html)이 발생합니다 그걸로. 단일 스레드로이 예외가 발생할 수 있습니다. 목록에 동시에 액세스하는 다중 스레드가 없으면 어떤 유형의 동시 수집도 필요하지 않습니다. –

+0

예를 들어 http://ideone.com/pUPCn. –

답변

0

synchronized 블록이 작동해야하는 것처럼 보입니다. 나는 목록을 수정하는 블록 ReadObjectsynchronized 블록 내에서 호출 된 메소드에 활동이있을 것으로 기대합니다. MessageHandler 중 하나를 addNewLoggedInUser (또는 수신기 목록을 업데이트 할 수있는 다른 방법)에 대한 호출에 전화하거나 연결하십시오.

그렇다면이 스레드는 모니터가 이미 ReadObjectsynchronized 블록으로 움켜 잡고 addNewLoggedInUser에 블록을 입력 할 수 있습니다.

+0

예, MessageHandler의 addNewLoggedInUser 호출 중 하나입니다. 나는 "모니터"가 무엇인지 잘 모르겠다. 그래서 나는 그것에 대해 약간의 연구를해야 할 것이다. 팁 고마워. – Matthew

2

java.util.ConcurrentModificationException은 실제로 스레딩 문제가 아닙니다. iterator가 잠근 목록의 수정으로 인해 발생합니다. 내 생각에 addNewLoggedInUser()MessageReceived()으로 호출하는 것 같습니다. 호출 함수가 이미 링크 된 목록에 반복자 잠금을 가지고 있으므로 동시 변경 예외가 발생할 수 있습니다.

0

BlockingQueue javadoc을 (를) 수행하십시오. 사용자의 요구 사항에 맞는 간단한 시나리오를 언급합니다. 즉,

class Producer implements Runnable { 
    private final BlockingQueue queue; 
    Producer(BlockingQueue q) { queue = q; } 
    public void run() { 
    try { 
     while (true) { queue.put(produce()); } 
    } catch (InterruptedException ex) { ... handle ...} 
    } 
    Object produce() { ... } 
} 

class Consumer implements Runnable { 
    private final BlockingQueue queue; 
    Consumer(BlockingQueue q) { queue = q; } 
    public void run() { 
    try { 
     while (true) { consume(queue.take()); } 
    } catch (InterruptedException ex) { ... handle ...} 
    } 
    void consume(Object x) { ... } 
} 

class Setup { 
    void main() { 
    BlockingQueue q = new SomeQueueImplementation(); 
    Producer p = new Producer(q); 
    Consumer c1 = new Consumer(q); 
    Consumer c2 = new Consumer(q); 
    new Thread(p).start(); 
    new Thread(c1).start(); 
    new Thread(c2).start(); 
    } 
}