0

링크 된 목록에서 최대 값을 찾으려고하는 각각 4 개의 스레드가 있습니다. 왜이 변수를 동기화해야합니까?

내 스레드 클래스입니다 :

public class MyThread extends Thread { 

    LinkedList<Integer> list; 
    int max = Integer.MIN_VALUE; 

    public MyThread(LinkedList<Integer> list) { 
     this.list = list; 
    } 

    public void run() { 
     synchronized (list) {  /* If I don't synchronize list, I get a NoSuchElementException at list.remove() */ 
      while (!list.isEmpty()) { 
       int num = list.remove(); 

       if (num > max) { 
        max = num; 
       } 
      } 
     } 
    } 
} 

그리고 여기에 주요 방법으로 클래스 : 위의 코드에서

public class Application { 

    public static void main(String args[]) throws InterruptedException { 
     LinkedList<Integer> list = new LinkedList<Integer>(); 

     for (int i = 0; i < 10; i++) { 
      list.add(i); 
     } 

     MyThread t1 = new MyThread(list); 
     MyThread t2 = new MyThread(list); 
     MyThread t3 = new MyThread(list); 
     MyThread t4 = new MyThread(list); 

     t1.start(); 
     t2.start(); 
     t3.start(); 
     t4.start(); 

     t1.join(); 
     t2.join(); 
     t3.join(); 
     t4.join(); 

     System.out.println(t1.max); 
     System.out.println(t2.max); 
     System.out.println(t3.max); 
     System.out.println(t4.max); 
    } 
} 

, 나는 run 메소드 내에서 list 변수를 동기화 할 수 있습니다 그렇지 않으면 NoSuchElementExceptionlist.remove()에 도착합니다. 왜 이런 경우입니까?

각 스레드마다 고유 한 목록이 없으므로 스레드 간섭이 없습니다.

감사합니다.

+0

각각의'MyThread' 생성자는 동일한리스트 참조로 호출되므로, 모든 쓰레드는 같은리스트를 사용할 것입니다. – korolar

+2

각'Thread'에'List'를 넘겨 주면 왜 각자 자신의 복사본이 있다고 생각합니까? –

+0

[Javadoc 읽기] (https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html), 특히 굵게 표시된 비트는 "**이 구현은 동기화되었습니다. ** ". –

답변

1

내가 @Rishi가 해결하는 것이 질문의 다른 부분을 해결합니다

하지 않습니다 각 스레드에는 스레드 간섭이 없도록는 자신의 목록입니다 있나요?

간단한 대답은 다음과 같습니다. 아니요. Java에서는 클래스 유형의 객체를 생성자 또는 메서드에 전달할 때 obejct 자체를 전달하는 것이 아니라 포인터를 전달합니다. 링크 된 목록의 별도 사본을 각 스레드에 전달하려면 LinkedList#Clone을 사용해야합니다.

복제를 사용하면 스레드가 연결된 목록에서 정수를 하나 제거하면 다른 연결된 목록에서 제거되지 않습니다. 이것을 제대로 평행 화하려면 모든 숫자를 가진 표준 배열을 사용하고이 배열의 세그먼트를 각 스레드에 할당해야합니다 (즉, 스레드 1은 0-9, 스레드 2는 10-19, 스레드 3은 20-29, 기타.). 배열의 내용은 내용이 배열에 저장 된 후에 만들어진 모든 스레드에서 볼 수 있습니다.


또한 스레드를 확장해서는 안됩니다. 대신 Runnable을 확장하여 스레드에 전달하십시오. 게다가 배열 (리스트)은 4 개의 개별 변수보다 좋을 것입니다. 나중에 쉽게 스레드 수를 변경할 수 있기 때문입니다.

1

LinkedList는 스레드로부터 안전하지 않습니다. 따라서 둘 이상의 스레드로 LinkedList에서 작업하는 경우 외부 동기화가 필요합니다.

BlockingQueue을 사용할 수 있습니다.이 경우 poll() 메서드가 유용 할 수 있습니다.

+0

스레드 안전하지 않다는 것은 아닙니다. 'isEmpty()'와'hasNext()'가 원자 적으로 실행되지 않는다는 것입니다. 즉, 다른 스레드가'isEmpty()'가 false를 반환하도록하는 요소를 훔칠 수 있습니다. BlockingQueue에 +1하십시오. –