【问题标题】:How to handle wait() notify()?如何处理等待()通知()?
【发布时间】:2025-11-22 19:20:05
【问题描述】:

这里我有两个运行方法应该相互同步。

轮询类:

     */
public void run() {
    int seqId = 0;
    while(true) {
    List<KpiMessage> list = null;

        try{
            if(!accumulator.isUsed){                
                try {
                    list = fullPoll(seqId);

                    if (!list.isEmpty()) {
                        seqId = list.get(0).getSequence();
                        accumulator.manageIngoing(list);
                    }
                    System.out.println("Updated");                      
                    wait(); 
                } catch (Exception e1) {
                    e1.printStackTrace();

                }
            }

        } catch (Exception e){
            // TODO:
            System.err.println(e.getMessage());
            e.printStackTrace();                
        }
    }

}


/**
 * Method which defines polling of the database and also count the number of Queries
 * @param lastSeq 
 * @return pojo col
 * @throws Exception
 */
public List<KpiMessage> fullPoll(int lastSeq) throws Exception {
    Statement st = dbConnection.createStatement();
    System.out.println("Polling");
    ResultSet rs = st.executeQuery("Select * from msg_new_to_bde where ACTION = 814 and 
    STATUS = 200 order by SEQ DESC");
    List<KpiMessage> pojoCol = new ArrayList<KpiMessage>();
    try {


        while (rs.next()) {
            KpiMessage filedClass = convertRecordsetToPojo(rs);
            pojoCol.add(filedClass);
        }

        for (KpiMessage pojoClass : pojoCol) {
            System.out.print(" " + pojoClass.getSequence());
            System.out.print(" " + pojoClass.getTableName());
            System.out.print(" " + pojoClass.getAction());
            System.out.print(" " + pojoClass.getKeyInfo1());
            System.out.print(" " + pojoClass.getKeyInfo2());
            System.out.print(" "+ pojoClass.getStatus());
            System.out.println(" " + pojoClass.getEntryTime());

        }


    } finally  {
        try {
            st.close();
            rs.close();
        } catch (Exception e) {
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
    }       

处理和更新类:

        public void run() {
    while(true){
        try {
            while(!accumulator.isUsed)
            {
                try {
                System.out.println("Waiting for new outgoingmessages"); 
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
     Collection<KpiMessage> outgoingQueue = generate(accumulator.outgoingQueue); 
            accumulator.manageOutgoing(outgoingQueue, dbConnection);
        } catch (Exception e) {
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
    }
}
}   

我有一个逻辑错误:

轮询器不仅轮询新消息,而且还从第一个开始一次又一次地读取数据库。

也一次又一次地更新。

如何解决这个同步问题

【问题讨论】:

  • 您应该只包含代码的必需部分,而不是转储整个程序。更新db方法与IllegalMonitorStateException无关
  • @NarendraPathai 我已经更新了...
  • OP 之前也有同样的问题:*.com/questions/14772236/…

标签: java multithreading performance exception concurrency


【解决方案1】:

您也可以使用BlockingQueue 在线程之间传输数据。

详情请见BlockingQueue

// The end of the list.
private static final Integer End = -1;

static class Producer implements Runnable {
  final Queue<Integer> queue;
  private int i = 0;

  public Producer(Queue<Integer> queue) {
    this.queue = queue;
  }

  @Override
  public void run() {
    try {
      for (int i = 0; i < 1000; i++) {
        queue.add(i++);
        Thread.sleep(1);
      }
      // Finish the queue.
      queue.add(End);
    } catch (InterruptedException ex) {
      // Just exit.
    }
  }
}

static class Consumer implements Runnable {
  final Queue<Integer> queue;
  private int i = 0;

  public Consumer(Queue<Integer> queue) {
    this.queue = queue;
  }

  @Override
  public void run() {
    boolean ended = false;
    while (!ended) {
      Integer i = queue.poll();
      if ( i != null ) {
        ended = i == End;
        System.out.println(i);
      }
    }
  }
}

public void test() throws InterruptedException {
  Queue queue = new LinkedBlockingQueue();
  Producer p = new Producer(queue);
  Consumer c = new Consumer(queue);
  Thread pt = new Thread(p);
  Thread ct = new Thread(c);
  // Start it all going.
  pt.start();
  ct.start();
  // Close it down
  pt.join();
  ct.join();
}

【讨论】:

  • 谢谢,这像fork join pool吗,因为这里使用线程池..我的代码不断更新,轮询器不仅读取新消息,还从首先...
  • ForkJoinPool 是 Java 7 的一个特性。这段代码没有使用它。这段代码所做的只是演示使用BlockingQueue 在两个线程之间进行通信是多么简单。使用wait/notify 不仅要复杂得多,而且是一个充满警告和危险的雷区。
  • “等待/通知是雷区”——说真的,我会尝试实施阻塞队列并返回谢谢...
  • *.com/questions/14772236/… 中有人告诉你如何避免 IllegalMonitorStateExceptions。也许您也应该查看 java.util.concurrent 中的更高级别的类。 BlockingQueues 已经在那里实现了。
  • @RalfH,我被 IllegalMonitorStateExceptions 清除了,但是现在在我的代码中出现了一个逻辑错误,我的代码从第一个重复轮询而不是只轮询新消息也重复更新....
【解决方案2】:

您应该同步或更确切地说是保持锁定或监控您正在调用wait()notify() 的对象。

以下是对您有帮助的:wait() throwing IllegalArgumentException

synchronized(lockObject){

     lockObject.wait(); //you should hold the lock to be able to call wait()
}

【讨论】:

  • 谢谢,是不是我添加了 Synchronized(lockObject) 而不是正常的等待。
  • lockOject 的名称是否与第一次运行方法的线程名称相对应。
  • 没有。您将拥有一个对象,该对象将在所有线程之间共享,并且所有线程都将锁定该对象并对该对象调用等待。并且一个线程将锁定并在同一个对象上调用通知。锁的名称与线程的名称无关。您应该阅读基本的线程教程。
最近更新 更多