1

我有三个类,一个代表一堆 url

    private Queue<String> queue = new LinkedList<String>();

    public Queue<String> getQueue() {
        return queue;
    }

    private int limit = 5;
    private int stillParsing;

    public synchronized String getNextString() throws InterruptedException {
        while (queue.isEmpty()||stillParsing > limit) {
            System.out.println("no for you "+ queue.peek());
            wait();
        }

        System.out.println("grabbed");

        notify();
        stillParsing++;
        System.out.println(queue.peek());
        return queue.remove();

    }

    public synchronized void doneParsing() {
        stillParsing--;
    }

}

一个线程类,其运行方法是

public void run(){
        try {
        sleep(30);
        for(;;){

              String currenturl = pile.getNextString();
              //(do things)
        }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            pile.doneParsing();
        }
    }

还有一个映射器,它使用这个片段实际上将对象添加到一堆 url 中

while (urls.hasMoreTokens()) {
                try{

                    word.set(urls.nextToken());
                String currenturl = word.toString();
                System.out.println(currenturl);
                pile.getQueue().add(currenturl);

从调试中我认为发生的是所有线程都试图在映射器有机会填充它之前立即从队列中获取它并且它们被卡住等待。不幸的是,所有等待的线程都导致我的程序挂起并且没有向队列中添加更多 url。我应该如何处理这个问题?最好在仍然使用等待通知时。

4

2 回答 2

4
while (urls.hasMoreTokens()) {
    try {
       word.set(urls.nextToken());
       String currenturl = word.toString();
       System.out.println(currenturl);
       pile.getQueue().add(currenturl);

在上面的代码中,您通过在队列中添加一些东西而不通过堆的方法来打破堆的封装。你不应该getQueue()在这个类中有一个方法:对这个共享数据结构的所有访问都应该在同一个锁上同步。因此,您应该添加一个同步方法,允许将 URL 添加到队列中。并且此方法还应该调用notify()(或更好notifyAll():),以唤醒正在等待某个元素进入队列的线程:

public synchronized void addUrl(String url) {
    queue.add(url);
    notifyAll();
}
于 2013-07-09T20:26:47.850 回答
1

即使没有阅读您的所有代码行和解释,我也可以说您对等待和通知的使用是错误的。

方法wait()是阻塞。notify()它仅在调用同一监视器时才退出。这意味着您不能将两者都放在wait()notify()一个线程中。你根本永远不会到达,notify()因为wait()永远被封锁。

其他版本的wait():wait(timeout)被阻止但受指定超时限制。此外,等待/通知对仅在将它们写入synchronized块时才起作用:

// thread-1
synchronoized(obj) {
    obj.wait();
} 


// thread-2
synchronoized(obj) {
    obj.notify();
} 

当线程 2 调用通知时,线程 1 将退出等待。

于 2013-07-09T20:26:11.487 回答