在一个循环中产生多个线程实例调用,程序如下:
public class testrun 
{
      public static void main(String[] args)
{
int i = 1 ;
for (i=1;i<100 ;i++ )
{
new test(i).start();
}
}}
class test extends Thread
{
private int iNum = 0;
boolean stoped = false;
public test(int num)
{
this.iNum = num ;
}
public void run()
{
synchronized (this) {
while (!stoped)
{
try
{
this.sleep(30);
}catch(Exception e) {
//
}
System.out.println("正在运行第" + iNum + "个线程!");
}
}
}
public void stoped()
{
this.stoped = true;
}
}运行结果,多个线程无限的在执行,而且顺序并不是从1到100,而是乱的,如果我采用stoped()方法来停止,我在main方法中如何调用????如何才能让线程一个接着一个的去执行?如何控制?其次,如果我的主程序中的循环量很大,比如说1亿次,甚至是100亿次,那将会产生100亿个线程实例,会不会有问题?应该如何处理?

解决方案 »

  1.   

    for (i = 1; i < 10000000; i++) {
    //循环量很大理论上没问题,不过i要定义为具有更大范围的如double等
                test t = new test(i);
                t.start();
                try {
                    Thread.sleep(100);//线程间启动有一定的延迟就ok了
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                t.stoped();//控制线程的结束
            }
      

  2.   

    你要顺序输出的话要这样!
    import java.util.*;
    public class testrun 
    {
        public static void main(String[] args)throws Exception{
    for (int i=1;i<100 ;i++ ){
    new test(i).join();
    }
    }}
    class test extends Thread{
    private int iNum = 0;
    public test(int num){
    this.iNum = num ;
    this.start();
    }
    public void run(){
    synchronized (this){
    System.out.println("正在运行第" + iNum + "个线程!");
    }
    }
    }sleep()也不是什么控制线程执行的办法。它只是暂停线程。唯一能保证的事情是,它会休眠至少100毫秒,但是它恢复运行所花的时间可能更长,因为在休眠结束之后,线程调度机制还要花时间来接管。
      

  3.   

    咨询一下,join和start,stop之间是什么关系?
    是不是在一个线程执行完以后才开始执行别的线程?
      

  4.   

    谢谢大家, interhanchi(闭关修练中!) 说的可以实现线程一个接一个的执行,但是我发现这样整个程序的运行时间比较长,比原来的时间更长,可否有好的解决方案,我这个程序的目的是,随机给出一个文件地址,http地址,产生一个线程去检测这个Web地址是否存在!
     // Run the Thread
        public void run()
        {
            synchronized(this) {
    //System.out.println(url);
                 CheckUrl(url);
             }
        }
     public void CheckUrl(String url)
       {
                //Util.ShowMessage("Start to Check the " + url);
    if(new Http().Get(url)) {
    Util.ShowMessage("OK");
    } else {
    Util.ShowMessage("Failure");
    }   }
    在CheckUrl方法中加入了检测web文件是否存在的判断,比如url="http://www.163.com/index.asp"
    如果存在就会显示"OK"
    但我发现这样在执行CheckUrl方法的时候,比原来的速度要慢很多,原来很快,但线程无法顺序执行,也不能产生正确的线程数量;按照interhanchi(闭关修练中!) 老兄的方法修改后,可以正确执行了,也就是用了join()方法,但速度却慢了,如何处理和优化,还有就是,假如有100亿次循环,产生100亿个线程,会不会出现问题,如何释放以前执行完了的线程??????
      

  5.   

    java线程运行结束后会(run()方法)自己释放资源,不用你担心;
    join()方法,只不过要求本线程结束后才调度与之关联的线程,线程越多运行速度越慢;
    你的问题本身就是矛盾的:既要顺序又要并发,不可能的
      

  6.   

    那如果并发,会不会出现同一个线程执行多次????而某一些线程却无法执行那?
    我测试过,如果采用start()方法调用,其产生的线程是乱的,而且一直不结束????为什么,应该如何处理?
      

  7.   

    恩,线程的本身时间就是不确定的,不仅是开始 结束时间,就是中间的执行时间也是不可预测的。
    所以不要用这么方法来处理这种事情。你可以用开辟一个队列来缓冲数据,
    然后用很多线程来轮询这个队列。比如 10000个,采用同步的方式读取队列中的元素,。
    当然你也可以根据实际的队列大小动态的增加或者减少队列个数。线程的模型如下。where(!stopFlag)
    {
      objData =queue.同步读并移除队列头元素方法();
      dealData();  
    }其中 queue对象 采用同步方法进行增加读取。
    模型类似一个生产者,多个消费者。
      

  8.   

    我采用start()方法,并发执行CheckUrl(url)方法,方法中使用了SOCKET的检测,但程序出现如下错误提示:
    Start to Check url www.163.com/xxx.asp
    .........................
    Connection timed out: connect
    No buffer space available (maximum connections reached?): JVM_Bind
    No buffer space available (maximum connections reached?): JVM_Bind
    No buffer space available (maximum connections reached?): JVM_Bind
    No buffer space available (maximum connections reached?): JVM_Bind
    Connection timed out: connect
    Connection timed out: connect
    Connection timed out: connect
    Connection timed out: connect
    Connection timed out: connect
    No buffer space available (maximum connections reached?): JVM_Bind
    No buffer space available (maximum connections reached?): JVM_Bind
    Connection timed out: connect
    Connection timed out: connect
    Connection timed out: connect
    Connection timed out: connect
    No buffer space available (maximum connections reached?): JVM_Bind
    Connection timed out: connect
    No buffer space available (maximum connections reached?): JVM_Bind
    No buffer space available (maximum connections reached?): JVM_Bind
    No buffer space available (maximum connections reached?): JVM_Bind
    No buffer space available (maximum connections reached?): JVM_Bind
    No buffer space available (maximum connections reached?): JVM_Bind
    No buffer space available (maximum connections reached?): JVM_Bind
    ..............................
    是不是并发的线程,在分别处理socket通信问题上出现了什么问题?????如何处理???其中程序如下:
     public boolean CheckUrl(String url)
        {
            try
            {
                if(CheckHttp(url))
                {
                    OpenServer(target.getHost(),target.getPort());
                    String cmd = "Get " + getURLFormat(target) + " HTTP/1.0\r\n"
                                 + getBaseHeads() + "\r\n";
                    sendMessage(cmd);
                    receiveMessage();
                                    if (responseCode!=200)
                                    {
                                            return false;
                                    }
                }
                            else
                            {
                                    return false;
                            }
            }
            catch(Exception e)
            {
                Util.ShowMessage(e.getMessage());
                return false;
            }
            return true;
        }/**
         *  CheckHttp方法检测当前请求的URL是否是有效的HTTP协议.
         */
      protected boolean CheckHttp(String httpUrl)
      {
          try
          {
                      URL target = new URL(httpUrl);
              if(target==null || !target.getProtocol().toLowerCase().equals("http"))
              {
                  Util.ShowMessage(httpUrl + "=========错误。原因是因为目标地址不是有效的HTTP协议==========");
                  return false;
              }
              this.target = target;
          }
          catch(MalformedURLException m)
          {
              Util.ShowMessage(m.getMessage());
              return false;
          }
          return true;
      }
    /**
       * 与Web服务器连接。若找不到Web服务器,InetAddress会引发UnknownHostException
       * 异常。若Socket连接失败,会引发IOException异常。
       */
     protected void OpenServer(String host,int port) throws
              UnknownHostException,IOException
      {
          header.clear();
          responseCode = -1;
          responseMsg = "";
          try
          {
              if(client != null)    {
                  CloseServer();
              }
              if(byteStream != null) {
                  byteStream.close();
                  byteStream = null;
              }
              InetAddress addr;
              try
              {
                  addr = InetAddress.getByName(host);
              }
              catch(UnknownHostException u)
              {
                  throw u;
              }
              client = new Socket(addr,(port==-1?80:port));
              sender = new BufferedOutputStream(client.getOutputStream());
              receiver = new BufferedInputStream(client.getInputStream());
          }
          catch(IOException e)
          {
              throw e;
          }
      }
    protected String getURLFormat(URL target)
      {
          String spec = "http://"+target.getHost();
          if(target.getPort()!=-1)
              spec+=":"+target.getPort();
          return spec+=target.getFile();
      }  protected String getBaseHeads() {
          String inf = "User-Agent: myself Http/1.0\r\n"+
                       "Accept: www/source; text/html; image/gif;application/data; */*\r\n";
          return inf;
    }
      /* 向Web服务器传送数据 */
      protected void sendMessage(String data) throws IOException{
          sender.write(data.getBytes(),0,data.length());
          sender.flush();
      }
      /* 接收来自Web服务器的数据 */
      protected void receiveMessage() throws IOException
      {
          byte data[] = new byte[1024];
          int count = 0;
          int word = -1;
    // 解析第一行      while ((word = receiver.read()) != -1) {
              if (word == '\r' || word == '\n') {
                  word = receiver.read();
                  if (word == '\n') word = receiver.read();
                  break;
              }
              if (count == data.length) data = addCapacity(data);
              data[count++] = (byte) word;
          }
          String message = new String(data, 0, count);
          int  = message.indexOf(32);
          serverVersion = message.substring(0, );
          while (>responseCode)
             {
                 responseCode = Integer.parseInt(message.substring( + 1, += 4));
             }
          responseMsg = message.substring(, message.length()).trim();// 应答状态码和处理请读者添加
          switch (responseCode) {
          case 400:
              throw new IOException("错误请求");
          case 404:
              throw new FileNotFoundException(getURLFormat(target));
          case 503:
              throw new IOException("服务器不可用");
              case 501:
                      throw new IOException("文件不能执行,或无法实现!");
          }      if (word == -1)throw new ProtocolException("信息接收异常终止");
    return ;
    }
    private byte[] addCapacity(byte rece[])
      {
          byte temp[] = new byte[rece.length + 1024];
          System.arraycopy(rece, 0, temp, 0, rece.length);
          return temp;
      }
      

  9.   

    线程调度是根据一定的策略来瓜分cpu时间的。如果很不幸在你的线程只抢到一点时间的话,那么不饿死也差不多了
      

  10.   

    你的意思是在线程产生的时候就将产生的线程放在一个队列中,然后在执行某个一个线程的时候,将其他的线程往队列里放,但当前线程执行完成后在去执行下一个线程,对吗?比如我采用一个hashTable来作为线程的一个队列存储器,那我如何将新产生的线程存入其中,或者如何读出来执行呢??请赐教!谢谢了!到时候我给你们加分!!!!!!
      

  11.   

    sjjf(水晶剑锋) 兄,象你说的那样,我的这个应该如何处理,用hashtable可不可以,如何处理呢?
    还有CheckUrl方法中执行了socket的程序,所耗费的时间相对较长,如何控制才好,谢谢了!
      

  12.   

    你看看这篇blog 对你有用否?
    http://blog.csdn.net/cozmic/archive/2005/08/16/455584.aspx
      

  13.   

    我的意思:  刚开始时候就用一个同步的队列。然后创建好一大堆线程(同一个线程类的)。
    这些线程的功能很简单是  取 队列里的头元素并进行处理的。
    而且是不断的运行的。
    你估算一下 处理一个数据需要多长时间比如是 t_deal。
    在一段时间内最多有多少 数据到达。比如 m个
    你需要的 达到的响应时间是 t_want.(t_want >= t_deal)
    假设你的机器比较牛x,刨除那些不良的小节的影响因素。
    你需要开辟的线程数 n 大致  m/(t_want/t_deal)<= n  <= m  
      

  14.   

    关于队列:
    package xxx.xxx.xxx
    import java.util.logging.*;
    import java.util.*;
    import ssts.util.*;
    /**
     * SyStaticSendQueue类构造一个用于多线程同步与互斥访问的静态队列,提供队列数据结构的相应访问.
     */
    public class SyStaticSendQueue {  private static List queue = Collections.synchronizedList(new LinkedList());
      private static Logger log = QueueLog.getLogger();/**
     * 提供一个具有同步与互斥操作的进队操作.<br>
     * 例如:String content = new String("0"+ id + data);<br>
     *      String len = String.valueOf(content.length());<br>
     *      content = len+content;<br>
     *      SyStaticQueue.enQueue( content );
     * @param  obj 进入队列的对象(例如:数据报文内容)
     * @return 无返回
     * @see    ssts.asycom.AsyCom
     */
      public static void enQueue( Object obj )
      {
        synchronized ( queue )
        {
          while( queue.size() >= 10240 )
          {
            log.finer("queue is full ! " + queue.size());
            try{
              queue.wait();
            }catch(Exception e)
            {
              e.printStackTrace();
            }
          }
          queue.add(obj);
           log.finer("queue size is : "+queue.size());
          queue.notifyAll();
        }
      }/**
     * 提供一个具有同步与互斥操作的出队操作.
     * @param  无
     * @return 队列中的对象
     * @see    ssts.asycom.AsyCom
     */  public static Object dlQueue()
      {
        Object obj = null;
        synchronized ( queue )
        {
          while( queue.isEmpty() )
          {
            try{
              queue.wait();
            }catch(Exception e)
            {
              e.printStackTrace();
            }
          }
          obj = queue.remove( 0 );
          log.finer("queue size is : "+queue.size());
          queue.notifyAll();
        }
        return obj;
      }
    /**
     * 提供一个具有同步与互斥操作的取对列头元素的操作.
     * @param  无
     * @return 排在队列中的第一个对象
     * @see    ssts.asycom.AsyCom
     */  public static Object getHead()
      {
        Object obj = null;
        synchronized ( queue )
        {
          while( queue.isEmpty())
          {
            try{
              queue.wait();
            }catch(Exception e)
            {
              e.printStackTrace();
            }
          }
          obj = queue.get( 0 );
        }
        return obj;
      }
    /**
     * 提供一个具有同步与互斥操作的判空操作.
     * @param  无
     * @return true 队列为空 false 队列非空
     * @see    ssts.asycom.AsyCom
     */
      public static boolean empty()
      {
        boolean flag = false;
        synchronized ( queue )
        {
          if( queue.isEmpty())
          {
            flag = true;
          }
          else
          {
            flag = false;
          }
        }
        return flag;
      }/**
     * 提供一个具有同步与互斥操作的取队列尺寸操作.
     * @param  无
     * @return 队列尺寸值
     * @see    ssts.asycom.AsyCom
     */
      public static int getSize()
      {
        int size = 0;
        synchronized ( queue )
        {
          size = queue.size();
        }
        return size;
      }
    }
      

  15.   

    // 消费数据的线程类  示意
    class  dealData extends Thread
    {
    private boolean runFlag = false;
    void run()
    {
    where(runFlag)
    {
    objData = SyStaticSendQueue.dlQueue()
    //在这里处理这些数据
    }
    }
    void setRunFlag(boolean xbFlag)
    {
    runFlag = xbFlag;
    }
    }// 数据生产类  示意 所有需要往这个队列里面增加需要处理元素的线程都采用下面的方式增加。class  appendData() 
    {
    public static void main(String[] args) 
    {
    SyStaticSendQueue.enQueue(objData);
    }
    }
    // 主控调度class  main_do() 
    {
    public static void main(String[] args) 
    {
    dealData workThread[xxx] ; 
    for (int i = 0 ; i < xxx ; i ++ )
    {
    workThread[i] = new dealData();
    workThread[i].setRunFlag(true);
    workThread[i].start();
    } // 需要关闭的时候 for (int i = 0 ; i < xxx ; i ++ )
    {
    workThread[i].setRunFlag(false);
    }
    } }
      

  16.   

    您好,为什么在 dealData workThread[xxx] ; 这句的时候编译不够呢?线程应该可以定义数组的呀,为什么???请各位指教
      

  17.   

    顺便再请教一下,如果使用
    vector v = new vector();
    for (int i = 0; i <num ; i++)
    {
      v.addElement(i);
    }如果其中的Num值非常大,比如说10亿(1000000000)时,程序运行中就会出现:Exception in thread "main" java.lang.OutOfMemoryError的错误,请问如何处理才不会出现这样?vector支持的最大值时多少?
      

  18.   

    跟踪发现当num值大于362638的时候,就会出现:Exception in thread "main" java.lang.OutOfMemoryError的错误,我的num值非常大,应该如何处理???谢谢各位了,一起进步............
      

  19.   

    起初我以为与自身机器的内存有关,我跟踪的时候发现,内存和CPU的占用量都不是很高,应该不会有问题的呀?可能是vector所允许的值,不知道如何解决.
      

  20.   

    看源代码,首先确定 vector的元素下表使用int型的存储,在32位系统里,它的能保存的个数不会超过 2的32次方(4G) 个 元素。
     实际上系统还把最高位当作符号位了 有效为只有 31位 ,再看着两个函数。
    public synchronized void addElement(Object obj) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);  
    elementData[elementCount++] = obj;
        }    private void ensureCapacityHelper(int minCapacity) {
    int oldCapacity = elementData.length;
    if (minCapacity > oldCapacity) { //如果最小的需要存储的个数大于 已有的空间。
        Object oldData[] = elementData;
    //如果指定了增长个数,则按照 旧的空间大小加上增长的空间大小 来确定新空间大小。
    //否则按照两倍的旧空间大小来确定新空间大小。
        int newCapacity = (capacityIncrement > 0) ?   
    (oldCapacity + capacityIncrement) : (oldCapacity * 2);   //如果确定的新空间大小仍然小于最小需要存储的空间大小。则新空间大小更改为最小需要存储空间的大小
             if (newCapacity < minCapacity) {
    newCapacity = minCapacity;
        }
        elementData = new Object[newCapacity];
    //拷贝旧的空间内容到新的空间大小里面来。
        System.arraycopy(oldData, 0, elementData, 0, elementCount);
    }
        }//在这种情况下outofmemory很大部分是因为  虚拟机分配的内存和堆栈空间太小。
    //在研究一下源码,如果预计在一段时间内会很频繁很大量的使用vector来存放东西,那么
    //最简单的策略是一次性给他分配齐了。当然也可以根据需要来定制内存分配策略。
    //下面是例子,运行通过的
    // 关于虚拟机的选项 具体参考 (随便搜的)
    // http://www.apple.com.cn/developer/Documentation/Java141Development/VM_Options/chapter_11_section_1.htmlimport java.util.*;
    class TestVector 
    {
    public static void main(String[] args) 
    {
    // Integer.MAX_VALUE == 2147483647 Vector aa = new Vector(Integer.MAX_VALUE,0); System.out.println("Hello World!");
    }
    }java -Xms256m -Xmx256m  TestDown
      

  21.   

    非常感谢sjjf(水晶剑锋)
    我在我的机器上测试了您的代码,如下:
    import java.util.*;
    public class test
    {
    public static void main(String args[])
    {
    int MAX_VALUE = 2147483647;
    Vector v = new Vector(MAX_VALUE,0);
    System.out.println("OK");
    }
    }D:\java>java -Xms256m -Xmx256m  test
    Exception in thread "main" java.lang.OutOfMemoryError为什么我的机器上还是不行呢?我把256M,换成512M也不行,我的机器是P4 2.8G+1G(Memory),是不是还有什么地方我写的不对 ????
      

  22.   

    我将自定义的maxValue修改成默认的,问题依旧:D:\java>type test.java
    import java.util.*;
    public class test
    {
            public static void main(String args[])
            {
                    Vector v = new Vector(Integer.MAX_VALUE,0);
                    System.out.println("OK");
            }
    }
    D:\java>javac test.javaD:\java>java -Xms256m -Xmx256m  test
    Exception in thread "main" java.lang.OutOfMemoryErrorD:\java>不知什么原因???
      

  23.   

    我的
    开发环境:  window 2000 server  p42.5 512m   
    编辑环境: editplus 
    编译环境: j2sdk1.4.1_02你换一个机器试一下我运行通过了之后才发上去的。
    在不加上  -Xms256m -Xmx256m   
    会出现 OutOfMemoryError
    加上之后就没有了,
    我怀疑是环境问题。
      

  24.   

    每个对象都要占有内存, 虚拟机内存 MAX_VALUE = 2,147,483,647 有两个G, 虚拟机即使有512M, 每个对象只能分到1/4个字节, 呵呵, 不溢出才怪.LZ把问题扯得挺远的, 我看顺序多线程本来就是一个矛盾命题. 我看只有搞清楚你的业务模型, 到底是顺序, 还是并发. 或者是在并发后才顺序, 只有这样才能有一个真正好的解决方案
      

  25.   

    说的很对,我现在就是没有搞清楚,究竟那个先,那个后,或者应该如何处理,我把我的业务描述出来,请大家给我点意见:(功能实际很简单)
    1、从字符集中产生指定位数的所有排列和组合
    2、将产生的每个组合字符串与http服务器上的文件进行比较,判断是否存在
    3、成功时将当前字符串存入文本第一步已经完成(以前采用生成后的字符组合存入文本文件,后来结果太大,放弃存入文件);
    第二步中的检测功能已经完成,由于第一步中没有采用存入文本文件,我设想在每产生一个字符组合后,就将该字符组合进行第二步的处理,当第二步完成后,重复第一步产生下一个........程序描述:
       第一步(循环产生所有的排列组合)  
       {
            if (产生单个排列组合 ) 
             {
                 第二步检测http文件;
                 if (成功) 第三步;
              }
       }
      

  26.   

    开发环境:  window 2003 server  p42.8 1024m   
    编辑环境: editplus 
    编译环境: j2sdk1.4.1_02
    vector v = new vector(Integer.MAX_VALUE,0);
    这种方式没能通过,不知到象上面我所描述的功能,是不是应该如此使用(其中产生了多线程的循环问题):
    程序描述:
       第一步(循环产生所有的排列组合)  
       {
            if (产生单个排列组合 ) 
             {
                 *****多线程执行(第二步检测http文件)*****;
                 if (成功) 第三步;
              }
       }
      

  27.   

    我再试了一下。很汗颜,这次居然不能运行。
    但是我确实是已经运行成功之后才发上去的,代码很短,
    我没有记错。后来我该了一下代码。import java.util.*;
    class TestVector 
    {
    public static void main(String[] args) 
    {
    // Integer.MAX_VALUE == 2147483647 int iSize = 100*1024*1024; //100m Vector aa = new Vector(iSize,0); System.out.println("Hello World!");
    }
    }当 iSize == 100M 时在 
    java -Xms512m -Xmx512m TestVector
    下能运行 
    但在 java -Xms256m -Xmx256m TestVector 就不行了(也成功过1次)。
    当 iSize == 300M 时
    在 java -Xms512m -Xmx512m TestVector
    我只成功过2次,其他次都不行。很奇怪。
    我的机器内存才 512M 不能在增加 -Xmx 了。 你跟boss申请内存吧,呵呵 然后再增大
      

  28.   

    业务描述:
    1. 产生排列组合串
    2. 根据提供的串排列组合匹配数据
    3. 符合匹配数据的内容做特殊处理算法描述:
      1. 主线程做字符串串排列组合, 得到串后将其写入一个读取队列A(需要限定队列的总长度)
      2. 建立线程池(数量可设定), 线程池中线程扫描并读取队列A, 并做数据匹配动作
      3. 如果匹配成功, 将数据写入输出队列B. 线程池做下一次匹配处理
      4. 由特殊处理线程(或线程组)扫描输出队列B, 做相应的特殊处理
      

  29.   

    对,就是全排列。TinyJimmy(Jimmy)的描述很正确,我目前采用的方法也是这样,但是,在得到串后将其写入一个读取队列A(需要限定队列的总长度)时,这个队列的长度超出了系统所能使用的最大值,比如我的队列A采用Vector,当addElement的时候,循环超过362637时就会出现上面说过的outofMemory的错误,不知道这个环节如何处理了?
      

  30.   

    给楼主贴的代码就是这个意思,不过没有输出队列。
    原模型如下:
    输入接受处理===> 输入缓冲 ==〉主处理 ==>输出缓冲 ==>输出处理
    其中 输入接受处理,主处理 ,输出处理 都是并发的且缓冲区两侧都遵循
    生产者消费者模型。当然在实现上不是太严格。其实也不一定要输出缓冲。就看那个部分性能评价的权比较大。
    楼主为什么要让这个队列超出这个长度呢?
    输入队列不是有长度吗?为什么不用它来做限制?
    如果缓冲满的话,就会暂停输入的。
    缓冲空的话也会暂停读取的。
      

  31.   

    就象上面所提供的方法:
    我在使用循环调用enQueue()方法,当size()>100K时就等待,但屏幕显示waiting..........,后就一直不动了,那这样岂不是无法执行下去,或者速度很慢了??????????????
    public static void enQueue( Object obj )
      {
     
        synchronized ( queue )
        { 

          if( queue.size() >= 100 * 1024 )
          {
    System.out.print("Waiting..........");
            try{
              queue.wait();
            }catch(Exception e)
            {
              e.printStackTrace();
            }
          }
      
          queue.add(obj);
          queue.notifyAll();
        }
      }
      

  32.   

    处理1===> 输入缓冲1 ==〉处理2 ==>输出缓冲2 ==>处理3本来你的 处理2 都不快,那么你的处理1 快了会有问题的。缓冲区也会被冲爆的。
    等待的目的就是要让处理1缓一下同步一下。