2012-03-12 6 views
0

동기화 된 블록을 이해할 수 있도록 도움이 필요합니다. 다음 예 가정 :자바 스레드 : synchronized blocks

public class ThreadStarter { 
    public static void main(String[] args) { 

     Queue queueObject = new Queue(); 

     ThreadA thread1 = new ThreadA(queueObject); 
     ThreadA thread2 = new ThreadA(queueObject); 

     ThreadB thread3 = new ThreadB(queueObject); 
     ThreadB thread4 = new ThreadB(queueObject); 

     thread1.start(); 
     thread2.start(); 

    } 
} 

public class Queue { 

    Object[] the theQueue; 

    public Queue(int size){ 
     theQueue = new Object[size]; 
    } 

    public submitObject(Object o){ 
     /* add Object to the queue */ 
    } 

    public deleteObject(int objectId){ 
     /*delete Object from the queue */ 
    } 
} 

public class ThreadA extends Thread { 

    private Queue queue; 

    public ThreadA(Queue queue){ 
     this.queue = queue; 
    } 

    public void run() { 
     while(!isInterrupted()){ 
      synchronized(queue) { 
       Object o = new Object 
       queue.submitObject(o); 
       /* do some other stuff */ 
     } 

     try { 
      sleep((int)(Math.random()*1000)); 
     } catch (interruptedException) { 
      Thread.currentThread().interrupt; 
     } 

      synchronized(queue) { 
       /* do some other stuff on the queue */ 
      } 
     } 
    } 
} 

public class ThreadB extends Thread { 

    private Queue queue; 

    public ThreadB(Queue queue){ 
     this.queue = queue; 
    } 

    public void run() { 
     while(!isInterrupted()){ 
      synchronized(queue) { 
       queue.deleteObject(o); 
       /* do some other stuff */ 
     } 

     try { 
      sleep(1000); 
     } catch (interruptedException) { 
      Thread.currentThread().interrupt; 
     } 
    } 
} 
} 

내 질문은, 안전을 위해, 큐 클래스에 개체를 제출 ThreadA에서 전체 큐 개체를 동기화 충분히입니까? ThreadB에서 큐에서 객체를 삭제하기 위해 동일한 작업을 수행했습니다. 또는 Queue 클래스의 submitObject() 및 deleteObject() 메서드를 동기화해야합니까?

위와 같이 스레드의 전체 Queue 클래스를 잠그면, 안전한 측면에 있어야합니다. 맞습니까?

greetZ 및 미리 감사드립니다.

답변

2

두 스레드가 동시에 submitObject & deleteObjecct 안에 들어갈 수 없도록해야합니다. 이를 달성하기 위해, 단지 동기화 된 메소드를 선언하십시오. 그런 경우 클래스간에 공유되는 큐 객체는 동기화되는 블록에서 2 개의 스레드가 멈추는 것을 방지합니다.

당신이 원하는 경우, 또한, 같은 메커니즘을 차단하는 어떤 종류의를 가지고 :

"스레드가 개체를 삭제하고자하는 경우, 그것은에서 그러한 객체 가없는 경우 대기해야 열." 객체가 이용 가능하게 될 때까지, 두 가지 방법이 여전히 동기화되어야하지만 DeleteObject 매크로에 입력 스레드가 큐에 의해 this.wait 사용을 중단해야합니다 :

는 그냥 그런 식으로 동기화하는 것보다 더 많은 일을 할 필요가

public synchronized deleteObject() { 
    while(isEmpty()) { 
    try { 
     wait(); 
    } catch(Exception ex) { 
     ex.printStackTrace(); 
    }//catch 
    }//while 

    //actually do delete object. 
    ... 
}//met 

및 다음을 수행하여 대기 상태에있는 스레드를 통보해야 submitObject : 당신은 또한 역할을 건너에 대한에 두 가지 방법으로 몇 가지 코드를 추가 할 수 있습니다 및

public synchronized submitObject() { 
    //do put object 
    ... 
    notifyAll(); 
}//met 

을 대기열이 가득 차면 제출자를 차단하고 대기열에 남아있는 공간이있을 때 통지합니다.

1

내가 submitObjectdeleteObject 방법에 큐 개체에 동기화 할 것이며,이 의미 충분해야한다 :

public submitObject(Object o){ 
    synchronized (theQueue) { 
     ... 
    } 
} 

public deleteObject(int objectId){ 
    synchronized (theQueue) { 
     ... 
    } 
} 
1

당신이 할 것은 당신의 queue 인 (public synchronized method()this와 동기화 방법을 동기화하는 것과 같습니다 지역 변수)를 제외하고는 큐를 사용할 때마다이를 수행해야한다는 것을 기억해야합니다. 제출 및 삭제 방법을 동기화하는 것이 더 안전합니다 .... 동기화 된 블록에서 Object o = new Object()도 제거됩니다.

+0

+1 : 동기화를 캡슐화할수록 더 쉽고 안전합니다. –

+1

'queue'의 메소드를 동기화하는 것과 기능상 동일하지 않습니다. 그가 그렇게했다면 각'synchronized '섹션에서 발견되는'/ * do some other stuff * /'는 중요한 섹션에 있지 않고 병렬로 실행될 수 있습니다. 해당 코드의 내용에 따라 동기화하는 것이 중요 할 수도 있습니다. 이는 동기화 된 목록과 유사합니다. 반복적으로 여러 작업을 수행하려는 경우 (예 : 반복 작업) 여전히 목록에서 외부 동기화해야합니다. –

+0

@MaxPeters 완전히 동의합니다. – assylias