2011-02-02 2 views
6

나는 훈련 목적으로 Java에서 간단한 동기화 된 Stack 객체를 만들었습니다. 여기 내가 무슨 짓을 :SynchronizedStack 클래스를 올바르게 작성하는 방법은 무엇입니까?

여기
public class SynchronizedStack { 
    private ArrayDeque<Integer> stack; 

    public SynchronizedStack(){ 
     this.stack = new ArrayDeque<Integer>();  
    } 

    public synchronized Integer pop(){ 
     return this.stack.pop(); 
    } 

    public synchronized int forcePop(){ 
     while(isEmpty()){ 
      System.out.println(" Stack is empty"); 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     return this.stack.pop(); 
    } 

    public synchronized void push(int i){ 
     this.stack.push(i); 
     notifyAll(); 
    } 

    public boolean isEmpty(){ 
     return this.stack.isEmpty(); 
    } 

    public synchronized void pushAll(int[] d){ 
     for(int i = 0; i < d.length; i++){ 
      this.stack.push(i); 
     } 
     notifyAll(); 
    } 

    public synchronized String toString(){ 
     String s = "["; 
     Iterator<Integer> it = this.stack.iterator(); 
     while(it.hasNext()){ 
      s += it.next() + ", "; 
     } 
     s += "]"; 
     return s; 
    } 
} 

내 질문은 다음과 같습니다

  • 그것을 확인 isEmtpy() 방법을 동기화하지가가? 그것은 다른 스레드가 스택을 동시에 수정하는 경우에도 일관된 결과를 반환하기 때문입니다 (초기 또는 최종가 아닌 isEmpty 상태로 들어갈 작업이 없습니다). 아니면 동기화 된 객체의 모든 메소드를 동기화하는 것이 더 나은 설계입니까?

  • 나는 forcePop() 메소드를 좋아하지 않습니다. 요소를 팝업하기 전에 항목이 스택으로 푸시 될 때까지 기다릴 수있는 스레드를 만들고 싶습니다. 스레드의 run() 메서드에서 wait() 루프를 수행하는 것이 가장 좋은 방법이라고 생각했지만 그것이 IllegalMonitorStatException을 던지기 때문에. 이런 식으로하는 적절한 방법은 무엇입니까?

  • 다른 의견이나 제안이 있으십니까?

고맙습니다!

+1

메서드를 잠그지 말고, 개체를 잠그는 것을 선호하십시오. 읽어보기 : http://download.oracle.com/javase/tutorial/essential/concurrency/locksync.html –

+0

스택은 이미 동기화 된 벡터를 확장합니다. 컬렉션의 다른 선택이 훈련 연습을 위해 더 좋을 수도 있습니다. –

+0

Don Roby : 예, axtavt가 지적한대로 ArrayDeque를 사용하고 있습니다. – nbarraille

답변

7
  • Stack 자체가 이미 동기화, 그래서 (당신이 비 동기화 스택 구현을 원하는 경우 ArrayDeque 사용)

  • 그것은 사실을 제외하고 (는 허용되지 않습니다 다시 동기화를 적용 할 수 이해가되지 않습니다 이전 지점에서), 동기화 부족으로 인해 메모리 가시성 효과가 발생할 수 있습니다.

  • forcePop() 매우 좋습니다.그것은 차단할 수있는 차단 방법의 계약을 따르기 위해 붙잡지 않고 InterruptedException을 전달해야합니다. Thread.interrupt()을 호출하여 forcePop() 호출에서 차단 된 스레드를 인터럽트 할 수 있습니다.

+0

Stack/ArrayDeque 구현에 의존하지 않고 이것을 코딩했다고 가정하지만, 일관성없는 isEmpty() 결과를 유발할 수있는 전이 상태가없는 방식으로 배열을 사용한다고 가정합니다. 동기화하는 것이 더 빠르지 않거나 어쨌든 동기화하는 것이 더 안전할까요? – nbarraille

+0

어쨌든 동기화하십시오. 일부 동기화가 없으면 isEmpty() 호출에서 다른 스레드의 업데이트를 볼 수 없습니다. – Sbodd

0

isEmpty()을 동기화하지 않는 유일한 문제는 어떤 일이 발생하는지 알 수 없다는 것입니다. 귀하의 추론은 합리적이지만 합리적인 방식으로 기본 동작 인 Stack도 작동한다고 가정합니다. 이것은 아마도이 경우에 해당 할 수 있지만, 일반적으로 그 것에 의지 할 수는 없습니다.

질문의 두 번째 부분은 블로킹 팝 조작에는 아무런 문제가 없습니다. 가능한 모든 전략을 완벽하게 구현하려면 this을 참조하십시오.

또 다른 제안 : 응용 프로그램의 여러 부분 (또는 여러 응용 프로그램)에서 재사용 할 수있는 클래스를 만드는 경우 synchronized 메서드를 사용하지 마십시오. 대신이 작업을 수행합니다 :

public class Whatever { 
    private Object lock = new Object(); 

    public void doSomething() { 
    synchronized(lock) { 
     ... 
    } 
    } 
} 

그 이유하는 클래스의 사용자가 Whatever 인스턴스 여부에 동기화하려면 당신이 정말로 모르는 것입니다. 만약 그렇다면, 수업 자체의 운영에 방해가 될 수 있습니다. 이렇게하면 아무도 간섭 할 수없는 자신 만의 비밀 잠금 장치가 생깁니다.

0

stack.isEmpty()은 동기화가 필요하지 않지만 제어 할 수없는 클래스의 구현 세부 사항에 의존한다고 가정합니다. Stack의 javadocs에서는 클래스가 스레드로부터 안전하지 않으므로 모든 액세스를 동기화해야합니다.

0

나는 숙어를 조금씩 혼합하고 있다고 생각합니다. SynchronizedStackjava.util.Stack으로 백업하고 java.util.Vectorsynchronized을 백업합니다. 나는 다른 클래스의 wait()notify() behaivor를 캡슐화해야한다고 생각합니다.

관련 문제