关于Java并发程序的一个奇怪错误(使用信号量)



我遇到了一个问题,即每次程序填充阵列列表缓冲区中的所有位置时,程序都会停止执行。但是,从理论上讲。消费者流程仍然可以进入get()函数,导致Nockempty信号的信号值现在达到10个。因此,在消费者流程将信号值释放回信号eotfull之后,生产者过程仍然可以工作。

但它只是停止,我找不到问题。

这是程序:

import java.util.List;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.Semaphore;
/**
 * A bounded buffer maintains a fixed number of "slots". Items can be
 * inserted into and removed from the buffer. The buffer has a maximum
 * size.
 */
class BoundedBuffer2
{
  // the maximum size of the bounded buffer
  final public static int MAXSIZE = 10;
  Semaphore notEmpty = new Semaphore(0);
  Semaphore notFull = new Semaphore(MAXSIZE);
  Semaphore sema = new Semaphore(1);

  // the buffer
  volatile List<Integer> buffer;
  public BoundedBuffer2()
  {
    buffer = new ArrayList<Integer>();
  }
  // add an element to the end of the buffer if it is not full
  public synchronized void put(int input)
    throws InterruptedException
  {
      notFull.acquire();
      sema.acquire();
      buffer.add(input);
      sema.release();
      notEmpty.release();
  }
  // take an element from the front of the buffer
  public synchronized int get()
    throws InterruptedException
  {
      notEmpty.acquire();
      sema.acquire();
      int result = buffer.remove(0);
      sema.release();
      notFull.release();
      return result;
  }
  public int size()
  {
    int result = buffer.size();
    return result;
  }
}
/**
 * An instance of the Producer class produces new integers at random
 * intervals, and inserts them into a bounded buffer.
 */
class Producer2 extends Thread
{
  // the buffer in which to insert new integers
  BoundedBuffer2 buffer;
  public Producer2(BoundedBuffer2 buffer)
  {
    this.buffer = buffer;
  }
  public void run()
  {
    Random random = new Random();
    try {
      while (true) {
    Thread.sleep(100);
    //insert a random integer
    int next = random.nextInt();
    buffer.put(next);

    System.err.println("b.size() increases to " + buffer.size());
      }
    }
    catch (InterruptedException e) {}
  }
}
/**
 * An instance of the Consumer class consumes integers from a bounded
 * buffer at random intervals.
 */
class Consumer2 extends Thread
{
  // the buffer in which to insert new integers
  BoundedBuffer2 buffer;
  public Consumer2(BoundedBuffer2 buffer)
  {
    this.buffer = buffer;
  }
  public void run()
  {
    Random random = new Random();
    try {
      while (true) {
    Thread.sleep(200);
          //get the next integer from the buffer
    int next = buffer.get();
    System.err.println("next = " + next);
    System.err.println("b.size() reducted to " + buffer.size());

      }
    }
    catch (InterruptedException e) {}
  }
}
public class UseBuffer2
{
  public static void main(String [] args)
  {
    BoundedBuffer2 buffer = new BoundedBuffer2();
    Producer2 p = new Producer2(buffer);
    Consumer2 c = new Consumer2(buffer);
    p.start();
    c.start();
  }
}

这是控制台的输出:

b.size() increases to 1
b.size() increases to 2
next = 400524264
b.size() reducted to 1
b.size() increases to 2
b.size() increases to 3
next = 241523118
b.size() reducted to 2
b.size() increases to 3
next = -1618289090
b.size() reducted to 2
b.size() increases to 3
b.size() increases to 4
next = -316455080
b.size() reducted to 3
b.size() increases to 4
b.size() increases to 5
next = 338682909
b.size() reducted to 4
b.size() increases to 5
b.size() increases to 6
next = -961276708
b.size() reducted to 5
b.size() increases to 6
b.size() increases to 7
next = 2056804692
b.size() reducted to 6
b.size() increases to 7
b.size() increases to 8
next = -301063524
b.size() reducted to 7
b.size() increases to 8
b.size() increases to 9
next = -148582342
b.size() reducted to 8
b.size() increases to 9
b.size() increases to 10
next = -2076430410
b.size() reducted to 9
b.size() increases to 10

阅读同步关键字的工作方式:https://docs.oracle.com/javase/javase/tutorial/essential/essention/concurrency/concurrency/syncmeth.html

相关部分:

不可能在同步方法上进行两种调用 相同的对象交织在一起。当一个线程执行同步时 对象的方法,所有调用同步的其他线程 同一对象块的方法(暂停执行),直到第一个 线程是用对象完成的。

您的put()get()方法已同步。因此,如果生产者进入put()方法,请尝试获取notFull信号量,但不能因为缓冲区已满,它会永远阻止,并在输入同步方法时保持其获得的锁定。因此,消费者无法输入get()方法,也无法从缓冲区中删除元素。

最新更新