【问题标题】:Java wait/notifyAllJava 等待/通知全部
【发布时间】:2013-12-24 07:39:15
【问题描述】:

一个简单的线程程序,其中写入者放入堆栈,读取者从堆栈中弹出。

java.util.Stack;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class MailBox
{
   Stack<Integer> stack;

   static int num;

   public MailBox()
   {
       stack = new Stack<Integer>();

       num = 1;
   }
}

class Reader implements Runnable
{

   MailBox box;

   public Reader(MailBox box)
   {
       this.box = box;
   }

   public void run()
   {
       Thread.currentThread().setName("Reader " + MailBox.num++);

       for(int i = 0; i < 5; ++i)
       {
           synchronized (box)
           {
               try {

                   box.wait();

                   if(!box.stack.empty() && !box.stack.isEmpty())
                   {
                       int data = box.stack.pop();

  System.out.println(Thread.currentThread().getName() + " popped " + box.stack.pop());
                   }
                   else
                   {
                       System.out.println("Empty");
                   } 

               } catch (InterruptedException e) {
                   // TODO Auto-generated catch block
                   e.printStackTrace();
               }
           }

           try {
               Thread.currentThread();
               Thread.sleep(3000);
           } catch (InterruptedException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
           }
       }

   }
}

class Writer implements Runnable
{   
    MailBox box;

   public Writer(MailBox box)
   {
       this.box = box;
   }

   public void run()
   {
       int min = 1;
       int max = 3;

       Thread.currentThread().setName("Writer " + MailBox.num++);

       for(int i = 0; i < 5; ++i)
       {
           synchronized(box)
           {
               int data = (int)Math.random() * max + min;

               box.stack.push(data);

               System.out.println(Thread.currentThread().getName() + " pushed " + data);

               box.notifyAll();
           }

           try {
               Thread.sleep(3000);
           } catch (InterruptedException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
           }

        }

    }
}

public class Review 
{

   public static void main(String args[])
   {
       MailBox box = new MailBox();

       Writer writer = new Writer(box);

       Writer apprentice = new Writer(box);

       Writer publisher = new Writer(box);

       Reader reader = new Reader(box);

       Reader busy_reader = new Reader(box);

       Reader slow_reader = new Reader(box);

       Reader fast_reader = new Reader(box);

       Reader ugly_reader = new Reader(box);

       ExecutorService executor = Executors.newCachedThreadPool();

       executor.execute(writer);

       executor.execute(apprentice);

       executor.execute(publisher);

       executor.execute(reader);

       executor.execute(busy_reader);

       executor.execute(slow_reader);

       executor.execute(fast_reader);

       executor.execute(ugly_reader);

       executor.shutdown();

   }

}

程序似乎运行良好,只是读者偶尔会弹出一个空堆栈,从而生成 StackEmptyExceptions。

我有针对这种情况的保护措施,为什么会生成这些异常?

【问题讨论】:

    标签: java multithreading stack


    【解决方案1】:

    您将对象弹出两次:

    int data = box.stack.pop();
    System.out.println(Thread.currentThread().getName() + " popped " + box.stack.pop());
    

    正如您在documentation of stack 中看到的,pop 获取并删除数据。

    【讨论】:

    • 顺便阅读更多关于synchronized(...)waitnotify 的信息。 synchronized 实际上在其代码块之前调用 wait 并在代码块之后调用 notifyAll。所以你打电话给waitnotify 是没有意义的。更糟糕的是,在 synchronized 内部的对象上调用 notify 会做什么?
    • 我刚刚阅读了有关waitnotify 的更多信息。我上面说的不是真的,synchronized 不会“呼叫”那些。这些用于进一步的锁定逻辑。但是,如果您只是想让某个代码块一次只由一个线程执行,synchronized 就是为此。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多