2012-11-11 96 views
2

下面的代碼試圖將一個隨機值插入一個循環隊列中並將其刪除。但是,有一些同步問題。我知道我可以使用更高級別的例程,並且我將爲生產代碼執行此操作,但我很好奇爲什麼這不起作用?我在這裏錯過了什麼?爲什麼此代碼導致非法監視狀態異常?

public class CircularQueue { 
int count; 
int rear; 
int front; 
Object lock = new Object(); 
int size; 
int[] array; 
CircularQueue(int size) 
{ 
    this.size= size; 
    array = new int[size]; 
} 

void enqueue(int number) throws InterruptedException 
{ 
    if(isFull()) 
     lock.wait(); 

    synchronized(lock) 
    { 

     array[rear] = number; 
     System.out.println("Rear is:"+ rear+ "value is:"+number+"Size is:"+size); 

     rear = (rear+1)%size; 
     count++; 
    } 
    lock.notify(); 

} 

void dequeue() throws InterruptedException 
{ 
    if(isEmpty()) 
     lock.wait(); 

    synchronized(lock) 
    { 
     int retVal = 0; 
     retVal = array[front]; 
     System.out.println("Front is:"+ front+ "value is:"+retVal); 

     front = (front+1)%size; 
     count--; 
    } 

    lock.notify(); 

} 

boolean isFull() 
{ 
    if(count == size) 
    { 
     return true; 
    } 
    else 
     return false; 

} 

boolean isEmpty() 
{ 
    return count == 0; 
} 
} 

// Test類

import java.util.Random; 
public class App { 

    public static void main(String[] args) throws InterruptedException 
    { 
     final Random random = new Random(); 
     final CircularQueue circularQueue = new CircularQueue(10); 
     Thread t1 = new Thread(new Runnable(){ 

     @Override 
     public void run() { 
      try { 
       circularQueue.enqueue(random.nextInt(100)); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 

     }); 
     Thread t2 = new Thread(new Runnable(){ 

      @Override 
      public void run() { 
       try { 
        circularQueue.dequeue(); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 

      }); 

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

    } 

} 

回答

6

因爲java.lang.Object#waitjava.lang.Object#notifyjava.lang.Object#notifyAll必須從同步塊被調用。

作爲解決(需要檢查),你應該把你的條件synchronized塊內:

void enqueue(int number) throws InterruptedException 
{ 

    synchronized(lock) 
    { 
     if(isFull()) 
      lock.wait(); 

     array[rear] = number; 
     System.out.println("Rear is:"+ rear+ "value is:"+number+"Size is:"+size); 

     rear = (rear+1)%size; 
     count++; 
     lock.notify(); 
    } 
} 

void dequeue() throws InterruptedException 
{ 
    synchronized(lock) 
    { 
     if(isEmpty()) 
      lock.wait(); 

     int retVal = 0; 
     retVal = array[front]; 
     System.out.println("Front is:"+ front+ "value is:"+retVal); 

     front = (front+1)%size; 
     count--; 
     lock.notify(); 
    } 

} 
0

在此代碼中的另一個問題是,即使的isEmpty/isFull返回true - 直到調用相鄰等待隊列的狀態可能會改變。
例如:
- 隊列爲空
- 線程1調用的isEmpty()
- 上下文切換
- 線程2級的呼叫排隊(即現在的隊列不爲空)
- 上下文切換
- 線程1不調用lock.wait()事件雖然隊列不爲空

當wait()/ notify()調用將被放入同步塊中時,這個問題當然會解決。

相關問題