2014-09-29 2 views
0

동시성 질문 : 저는 Udemy.com에서 멀티 스레딩 과정을 밟을 것이며, 교사는 아래 코드를 통해 대화했습니다. 그는 설명했지만 여전히 list1list2에 잠글 때가 아니라 lock1lock2 개체를 만드는 이유가 확실하지 않습니다.동기화 : 다중 잠금 - 잠금 개체 만들기?

App.java :

public class App { 

    public static void main(String[] args) { 
     Worker worker = new Worker(); 
     worker.main(); 
    } 
} 

Worker.java : 그에 대한 의욕을 생각하지 않는다

import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 


public class Worker { 

    private Random random = new Random(); 

    private Object lock1 = new Object(); 
    private Object lock2 = new Object(); 

    private List<Integer> list1 = new ArrayList<Integer>(); 
    private List<Integer> list2 = new ArrayList<Integer>(); 

    public void stageOne() { 

     synchronized (lock1) { 
      try { 
       Thread.sleep(1); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

      list1.add(random.nextInt(100)); 
     } 

    } 

    public void stageTwo() { 

     synchronized (lock2) { 
      try { 
       Thread.sleep(1); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

      list2.add(random.nextInt(100)); 
     } 

    } 

    public void process() { 
     for(int i=0; i<1000; i++) { 
      stageOne(); 
      stageTwo(); 
     } 
    } 

    public void main() { 
     System.out.println("Starting ..."); 

     long start = System.currentTimeMillis(); 

     Thread t1 = new Thread(new Runnable() { 
      public void run() { 
       process(); 
      } 
     }); 

     Thread t2 = new Thread(new Runnable() { 
      public void run() { 
       process(); 
      } 
     }); 

     t1.start(); 
     t2.start(); 

     try { 
      t1.join(); 
      t2.join(); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     long end = System.currentTimeMillis(); 

     System.out.println("Time taken: " + (end - start)); 
     System.out.println("List1: " + list1.size() + "; List2: " + list2.size()); 
    } 
} 
+2

이유는 없습니다. 실제로'final' 변수에만 동기화해야합니다. 'List'를'final'으로 표시 할 수 있다면 간단히 동기화 할 수 있습니다. 별도의 객체를 사용하면 염려가 분리되고 코드가 명확 해지는 것으로 간주 될 수 있습니다. –

+2

Boris와 (과) 일치합니다. 한 포인트는 내가 getter에 의해 리턴 된 필드를 잠그고 싶지 않다는 것을 추가 할 것이다. 따라서 다른 용도로 사용되는 필드에서 잠금을 분리하면 이러한 가능성이 없어집니다. –

+0

감사합니다. @BoristheSpider와 @John B. 왜 'final' 변수에만 고정됩니까? 왜 getter를 사용하지 않습니까? –

답변

4

은 당신이 준 코드로 표현되어 있지만 은 일반적으로입니다 모범 사례. 그러나 동일한 모범 사례에서 잠금 개체는 final이어야합니다.

해당 목록을 외부에서 수락하거나 메서드를 통해 외부에 노출 한 경우 별도의 잠금 개체의 이점이 더욱 분명 해집니다. 자물쇠를 외부 코드에 노출하는 것은 결코 바람직하지 않습니다. 외계인 코드는 스스로 잠금을 사용하여 자신의 사용 패턴을 깨뜨릴 수 있습니다.

목록이 엄격하게 개인용이면 모니터를 내부 잠금에 사용할 수 있습니다. 그러나 나중에 목록의 액세스 정책을 변경하면 실수로 잠금 정책에 영향을 미칠 수 있습니다. 따라서 개인 잠금으로 시작하는 것은 향후 버그를 피하는 역할을합니다.

+0

굉장 - 여러 스레드가 액세스하는 객체를 잠그는 것이 합리적이라고 생각했지만 요점을 이해합니다. 매번 새로운'Object' 작품을 만들 것인가? 아직 배우는 동안 새 오브젝트가'List'와 관계가없는 것으로 보입니다. –

+2

어떤 경우에도 객체와 모니터 사이에는 관계가 없습니다. 단지 다른 모니터 일뿐입니다. 이 둘 사이의 유일한 접촉점은 메서드를 동기화 된 것으로 표시 할 수있는 다소 어색한 "편리한"구문입니다. 이 기능은 실제로 편의성보다 훨씬 더 혼란을 야기했습니다. –