在运行类

时间:2017-11-01 04:40:22

标签: java mutex semaphore

我试图用0和1设置一个简单的信号量,其中wait()函数和Signal()函数只允许临界区中的一个线程。

public class Producer extends BaseThread
{
    Semaphore semaphore = null;
    private char block; // block to be returned

    public Producer(Semaphore x)
    {
        this.semaphore = x;
    }
    public Producer()
    {
        // empty constructor
    }
    public void run()
    {

        try{
            this.semaphore.wait(); // enter the critical section
            for (int i = 0; i < 3; i++){
                this.block = StackManager.stack.pick();
                StackManager.stack.pick(); // return value on top
                StackManager.stack.push(block++); // pushes the next char value on the stack
            }
        }
        catch(Exception e){
            allException(e);
            System.exit(1);
        }
        finally
        {
            this.semaphore.Signal(); // end critical section
        }

    }
}

信号量在main中声明如下:

 static Semaphore lock = new Semaphore(-1); // create semaphore
 Consumer consumerSemaphore = new Consumer(lock);
 Producer producerSemaphore = new Producer(lock);

生产者和消费者信号量应该在主要交替中不会导致堆栈中的任何异常。 (我省略了Consumer类,因为它基本上与Producer一样,但是改为使用pop())。

现在的问题是,在运行我的代码时,我继续遇到Consumer和Producer类的NullPointerException错误,我似乎无法找到答案。我在这里缺少什么?

编辑: 代码应该是推送StackManager.stack顶部的下一个char值,但由于另一个名为Consumer的类也在执行尽可能多的pop()操作,因此需要执行synchronized。除了Semaphore之外,我无法使用其他任何东西,这是我创建的这个课程:

class Semaphore {
    private int value;

    public Semaphore(int value) {
        this.value = value;
    }


    public Semaphore() {
        this(0);
    }


    public synchronized void Wait() {
        while (this.value >= 0) { //changed to greater or equals since we're doing the opposite with natural numbers
            try {
                wait();
            }
            catch(InterruptedException e) {
                System.out.println ("Semaphore::Wait() - caught InterruptedException: " + e.getMessage() );
                e.printStackTrace();
            }
        }
        this.value++; // the semaphore value gets incremented since it needs to go to zero from -1 or lower
    }

    public synchronized void Signal() {
        --this.value; // signal decrements the value since it brings the lock back to -1 for the next wait operation
        notify();
    }

    public synchronized void P() {
        this.Wait();
    }

    public synchronized void V() {
        this.Signal();
    }
}

请注意,信号量在main()中初始化为-1,因为对于课程的复杂性,我们需要创建一个Semaphore类,其中-1表示为下一个线程做好准备,0表示某个线程在其关键部分。这意味着我写了wait()方法增量和信号减量。

编辑2:添加了消费者类

public class Consumer extends BaseThread {
    Semaphore semaphore = null;
    private char copy; // A copy of a block returned by pop()

    public Consumer(Semaphore x) {
        this.semaphore = x;
    }

    public Consumer() {
        // empty constructor
    }

    public void run() {
        try {
            this.semaphore.wait(); // enter the critical section

            System.out.println("Consumer thread [TID=" + this.iTID + "] starts executing.");
            for (int i = 0; i < StackManager.iThreadSteps; i++) {
                this.copy = StackManager.stack.pop(); // pop the top of the stack
                System.out.println("Consumer thread [TID=" + this.iTID + "] pops character =" + this.copy);
            }
            System.out.println("Consumer thread [TID=" + this.iTID + "] terminates.");
        } catch (Exception e) {
            allException(e);
            System.exit(1);
        } finally {
            this.semaphore.Signal(); // end the critical section

        }
    }
}

编辑3:

class StackManager {
    // The Stack
    public static CharStack stack = new CharStack();
    private static final int NUM_ACQREL = 4; // Number of Producer/Consumer threads
    private static final int NUM_PROBERS = 1; // Number of threads dumping stack
    public static int iThreadSteps = 3; // Number of steps they take
    // Semaphore declarations. Insert your code in the following:
    static Semaphore lock = new Semaphore(-1); // create semaphore
    Consumer consumerSemaphore = new Consumer(lock);
    Producer producerSemaphore = new Producer(lock);
    CharStackProber stackProberSemaphore = new CharStackProber(lock);
    // The main


    public static void main(String[] argv)
    {
        // Some initial stats...
        try
        {
            System.out.println("Main thread starts executing.");
            System.out.println("Initial value of top = " + stack.getTop() + ".");
            System.out.println("Initial value of stack top = " + stack.pick() + ".");
            System.out.println("Main thread will now fork several threads.");
        }
        catch(CharStackEmptyException e)
        {
            System.out.println("Caught exception: StackCharEmptyException");
            System.out.println("Message : " + e.getMessage());
            System.out.println("Stack Trace : ");
            e.printStackTrace();
        }
                    /*
                   * The birth of threads
                    */


        Consumer ab1 = new Consumer();
        Consumer ab2 = new Consumer();
        System.out.println ("Two Consumer threads have been created.");
        Producer rb1 = new Producer();
        Producer rb2 = new Producer();
        System.out.println ("Two Producer threads have been created.");
        CharStackProber csp = new CharStackProber();
        System.out.println ("One CharStackProber thread has been created.");
                  /*
                 * start executing
                  */
        ab1.start();
        rb1.start();
        ab2.start();
        rb2.start();
        csp.start();
                 /*
                  * Wait by here for all forked threads to die
                 */
        try
        {
            ab1.join();
            ab2.join();
            rb1.join();
            rb2.join();
            csp.join();
            // Some final stats after all the child threads terminated...
            System.out.println("System terminates normally.");
            System.out.println("Final value of top = " + stack.getTop() + ".");
            System.out.println("Final value of stack top = " + stack.pick() + ".");
            System.out.println("Final value of stack top-1 = " + stack.getAt(stack.getTop() - 1) + ".");
            System.out.println("Stack access count = " + stack.getAccessCounter());
        }
        catch(InterruptedException e)
        {
            System.out.println("Caught InterruptedException: " + e.getMessage());
            System.exit(1);
        }
        catch(Exception e)
        {
            System.out.println("Caught exception: " + e.getClass().getName());
            System.out.println("Message : " + e.getMessage());
            System.out.println("Stack Trace : ");
            e.printStackTrace();
        }
    }
}

堆栈跟踪如下:

    Main thread starts executing.
Initial value of top = 3.
Initial value of stack top = d.
Main thread will now fork several threads.
Two Consumer threads have been created.
Two Producer threads have been created.
One CharStackProber thread has been created.
Caught exception : java.lang.NullPointerException
Caught exception : java.lang.NullPointerException
Message          : null
Caught exception : java.lang.NullPointerException
Caught exception : java.lang.NullPointerException
Caught exception : java.lang.NullPointerException
Message          : null
Stack Trace      : 
Stack Trace      : 
Message          : null
Stack Trace      : 
Message          : null
Stack Trace      : 
Message          : null
Stack Trace      : 
java.lang.NullPointerException
    at Producer.run(Producer.java:18)
java.lang.NullPointerException
    at CharStackProber.run(CharStackProber.java:18)
java.lang.NullPointerException
    at Consumer.run(Consumer.java:19)
java.lang.NullPointerException
    at Consumer.run(Consumer.java:19)

为了保持这篇文章的简短,我省略了CharStackProber类,因为它只是Producer的副本,其中run()方法完全相同,但for循环的内部只是打印出StackManager.stack的元素

1 个答案:

答案 0 :(得分:0)

一个错误是您正在致电:

this.semaphore.wait()

而不是:

this.semaphore.Wait() . // (with capital 'W')

其次,看看这些内容:

    Consumer ab1 = new Consumer();
    Consumer ab2 = new Consumer();
    System.out.println ("Two Consumer threads have been created.");
    Producer rb1 = new Producer();
    Producer rb2 = new Producer();

您在没有将锁定传递给他们的情况下创建消费者和生产者,所以稍后当您尝试访问锁定时,您会看到NPE