2012-08-17 4 views
1

나는 아이템 목록을 가지고 있는데, 아이템을 체크했을 때,리스트의 끝 부분에있다. 응용 프로그램이 스레드로부터 안전하기를 바랍니다.Java의 목록에있는 항목의 순서를 변경하고 스레드 안전성을 유지하는 방법은 무엇입니까?

"checkItem"코드의 코드는 "items"목록과 관련하여 안전합니까?

public class ItemListImpl implements ItemList { 

     List<Item> items = Collections.synchronizedList(new ArrayList<Item>()); 

     /** 
     * Checks an item and brings it at the end of the list 
     */ 
     public void checkItem(int index) { 
      Item item = items.get(index); 
      item.check(); 

      synchronized (items) { 
       items.remove(item); 
       items.add(items.size(), item); 
      } 

     } 
    } 

(나는 항목의 인덱스를 사용한다는 사실을 잊는다. 나는 물체 또는 ID를 사용합니다)는 스레드 안전 확인하기 위해 다음과 같이 변경합니다

+0

'item.check()'의 기능은 무엇입니까? – Jeffrey

+0

항목의 개인 속성을 변경합니다 (isChecked = true) – mrmuggles

답변

2

우리는 items가 동기화 목록 실현해야하고, 동기화 된 목록은 원시적 뮤텍스로 자신을 사용하는. 즉, 모든 개별 목록 작업과 synchronized 블록이 items에서 동기화 중임을 의미합니다.

따라서 동기화되지 않은 방식으로 일어날 수있는 유일한 점은 get 호출 완료와 synchronized 블록 시작 간의 차이입니다. 그래서 그게 문제 죠?

잘 일어날 수있는 것을 고려 할 수 있습니다 :

  • 다른 스레드가 Item의 위치를 ​​이동하는 경우, 그것은 중요하지 않습니다. 우리는 어쨌든 그것을 끝까지 간단히 옮길 것입니다.

  • 다른 스레드가 Item을 제거하면 문제가되지 않습니다. remove으로 전화하면 false가 반환되지만 항목은 다시 추가됩니다.

문제는 주어진 Itemitems 목록에서 둘 이상의 위치에 표시하는 것이 가능한 경우 발생한다. 이 경우 코드가 items 요소를 잘못된 위치에서 목록의 끝으로 이동시킬 수 있습니다. 예 :

  1. 스레드 A의 전화는 (42) I ...하지만 이후 항목을 I.
  2. 스레드 B 삽입 항목 1.
  3. 스레드 A가 검사를 완료 위치에 I, 및 제거하고 readds 항목을 가져올 수 이제 위치 1에 나타납니다. 실제로 위치 42에있는 복사본이 아닌 해당 복사본을 제거하고 추가합니다.

즉, 주어진 Item 객체가 다음과 같은 경우에 코드는 스레드로부터 안전합니다. 목록에 한 번만 나타납니다. 그것이 우리가 가정 할 수 없다면, 우리는 잘못된 위치에서 물체를 움직일 위험이 있습니다.

주어진 항목이 두 번 이상 나타날 수있는 경우 코드가 제대로 작동하지 않습니다. 문제는 remove(item)이 찾은 item 인스턴스에 대한 첫 번째 참조를 제거하고 반드시 index에있는 참조를 제거하지 않아야한다는 것입니다. 이것을 보는 데는 두 가지 방법이 있습니다. 이 동작이 의도하지 않은 경우 버그입니다. 이것이 의도 된 것이라면, thread-safety 문제는 아마 논쟁 거리가 아닙니다.


하나의 방법은, 코드가 check 방법 스레드 안전하다고 가정하면, 메모리 모델에 대해 안전하다.

+0

+1, 훌륭한 설명 – Jeffrey

+0

감사합니다. – mrmuggles

0

합니다.

public void checkItem(int index) { 
      synchronized (items){  
       Item item = items.get(index); 
       item.check();   
       items.remove(item); 
       items.add(items.size(), item); 
      } 

    } 
+0

items.get 및 item.check를 동기화 된 블록에 넣어야하는 이유는 무엇입니까? – mrmuggles

관련 문제