【问题标题】:Why does this code result in illegalMonitorState exception?为什么这段代码会导致非法监视器状态异常?
【发布时间】:2012-11-11 20:55:53
【问题描述】:

下面的代码试图将一个随机值插入循环队列并将其删除。但是,存在一些同步问题。我知道我可以使用更高级别的例程,并且我将为生产代码这样做,但我很好奇为什么这不起作用?我在这里想念什么?

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;
}
}

// 测试类

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();

    }

}

【问题讨论】:

    标签: java java.util.concurrent


    【解决方案1】:

    因为必须从同步块中调用java.lang.Object#waitjava.lang.Object#notifyjava.lang.Object#notifyAll

    作为一种解决方案(需要检查),您应该将您的条件放在同步块中:

    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();
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      此代码中的另一个问题是,即使 isEmpty/isFull 返回 true - 在您调用相邻等待之前,队列的状态可能会发生变化。
      例如:
      - 队列为空
      - 线程 1 调用 isEmpty()
      - 上下文切换
      - 线程 2 调用入队(现在队列不为空)
      - 上下文切换
      - 尽管队列不为空,线程 1 不调用 lock.wait() 事件

      当调用 wait()/notify() 时,这个问题当然会解决。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-16
        • 2012-08-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多