notify()/wait()的Java问题

notify()/wait()的Java问题,java,wait,notify,Java,Wait,Notify,我在迭代器实例中有一个生成器,每次在迭代器上调用next时生成并返回一个项。这看起来确实很有效,但是我得到了返回的空值 类别代码: package spiral; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger;

我在迭代器实例中有一个生成器,每次在迭代器上调用next时生成并返回一个项。这看起来确实很有效,但是我得到了返回的空值

类别代码:

package spiral;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author student
 */
public class Spiral7DGenerator implements Iterator<List<Integer>> {
    private boolean releaseNext = false;
    private List<Integer> releaseList;

    public Spiral7DGenerator() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int t = 0; true; t++) {
                    loops(t);
                }
            }
        }).start();
    }

    @Override
    public boolean hasNext() {
        return true;
    }

    @Override
    public List<Integer> next() {
        synchronized(this) {
            releaseNext = true;
            notify();
            return releaseList;
        }
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    private void loops(int t) {
        for (int d1 = 0; d1 <= t; d1++) {
            for (int d2 = 0; d2 <= (t - d1); d2++) {
                for (int d3 = 0; d3 <= (t - d1 - d2); d3++) {
                    for (int d4 = 0; d4 <= (t - d1 - d2 - d3); d4++) {
                        for (int d5 = 0; d5 <= (t - d1 - d2 - d3 - d4); d5++) {
                            for (int d6 = 0; d6 <= (t - d1 - d2 - d3 - d4 - d5); d6++) {
                                int d7 = (t - d1 - d2 - d3 - d4 - d5 - d6);
                                generate(0, d1, d2, d3, d4, d5, d6, d7);
                            }
                        }
                    }
                }
            }
        }
    }

    private void generate(int pos, Integer... array) {
        if (pos == array.length) {
            List<Integer> list = new ArrayList<>();
            list.addAll(Arrays.asList(array));
            synchronized(this) {
                while (!releaseNext) {
                    try {
                        wait();
                    } catch (InterruptedException ex) {
                        Logger.getLogger(Spiral7DGenerator.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
            releaseNext = false;
            releaseList = list;
            return;
        }
        generate(pos + 1, array);
        array[pos] = -array[pos];
        if (array[pos] != 0) {
            generate(pos + 1, array);
        }
    }
}
测试输出:

test
s7dg.next() = null
s7dg.next() = null
s7dg.next() = null
s7dg.next() = null

恐怕这只是一件简单的事情,但我完全忽略了它。

我还没有完全理解您的代码,但我可以指出两点:

releaseList必须声明为volatile,至少在它被分配到同步块之外时是这样。 您的下一个方法不会等待通知的线程醒来并生成结果。这是一个比赛条件。您需要下一步等待一个额外的互斥锁或其他东西,以允许生成器通知已设置了releaseList。实际上,当您这样做时,您将不再需要使releaseList变得易变。
我还没有完全理解您的代码,但我可以指出两点:

releaseList必须声明为volatile,至少在它被分配到同步块之外时是这样。 您的下一个方法不会等待通知的线程醒来并生成结果。这是一个比赛条件。您需要下一步等待一个额外的互斥锁或其他东西,以允许生成器通知已设置了releaseList。实际上,当您这样做时,您将不再需要使releaseList变得易变。
这里的想法是工作线程向主线程提供一个结果流,对吗

我建议您不要试图手工构造并发控制逻辑,而是使用一个。代码如下所示:

public class Spiral7DGenerator implements Iterator<List<Integer>> {
    private BlockingQueue<List<Integer>> spirals = new SynchronousQueue<List<Integer>>();

    @Override
    public List<Integer> next() {
        return spirals.take();
    }

    private void generate(int pos, Integer... array) {
        if (pos == array.length) {
            List<Integer> list = new ArrayList<>();
            list.addAll(Arrays.asList(array));
            spirals.put(list);
            return;
        }
    // etc
    }
}

这里的想法是工作线程向主线程提供一个结果流,对吗

我建议您不要试图手工构造并发控制逻辑,而是使用一个。代码如下所示:

public class Spiral7DGenerator implements Iterator<List<Integer>> {
    private BlockingQueue<List<Integer>> spirals = new SynchronousQueue<List<Integer>>();

    @Override
    public List<Integer> next() {
        return spirals.take();
    }

    private void generate(int pos, Integer... array) {
        if (pos == array.length) {
            List<Integer> list = new ArrayList<>();
            list.addAll(Arrays.asList(array));
            spirals.put(list);
            return;
        }
    // etc
    }
}

你真的需要写这么复杂的代码吗。这对我来说是很难理解的。我在读取那些嵌套for循环时内存不足。@JunedAhsan虽然问题本身与代码无关,但我可以解释为什么它如此复杂。那是因为做螺旋线一般来说是复杂的,当然我想做一般的,而不是这个,但目前这对我来说太难了。你在Spiral7DGenerator const中的循环永远不会结束,每次迭代都会启动新线程。这是一个错误,因为内存有限。使用多个线程很少能让代码更简单。我仍然认为这更简单,更有可能解决另一个问题:您真的需要编写如此复杂的代码吗。这对我来说是很难理解的。我在读取那些嵌套for循环时内存不足。@JunedAhsan虽然问题本身与代码无关,但我可以解释为什么它如此复杂。那是因为做螺旋线一般来说是复杂的,当然我想做一般的,而不是这个,但目前这对我来说太难了。你在Spiral7DGenerator const中的循环永远不会结束,每次迭代都会启动新线程。这是一个错误,因为内存有限。使用多个线程很少能让代码更简单。我仍然认为这要简单得多,并且更有可能实现另一个答案,我怀疑是next根本不等待工作线程,这导致了所有的空值。关于releaseList和releaseNext也没有被安全地更新,您是绝对正确的。我怀疑是next根本没有等待工作线程导致所有空值。关于releaseList和releaseNext也没有安全更新,您完全正确。谢谢!这正是我需要的。尽管Java没有Python的收益率等价物,但它确实是如此。当然,Scala添加了continuations,让您可以构建生成器之类的东西。我认为这不太可能出现在Java中,事实上,这可能不是我想要的100%。我只想在螺旋上升时做些事情。BlockingQueue是否可以轻松修改,使其在spirals.size>threshold时阻塞?因为我希望它在spirals.size>0时阻塞/等待。然后等待,直到调用next,然后再次生成下一个元素,依此类推。实际上,spirals.put将阻塞,直到主线程出现并调用spirals.take为止,因此一次只有一个值通过队列。如果您想对队列的大小有更大的限制,但仍然是固定的,请将SynchronousQueue替换为所需容量的。啊,好的,SynchronousQueue确实正是我需要的,我应该在询问之前阅读文档。谢谢!这正是我需要的。尽管Java没有Python的收益率等价物,但它确实是如此。当然,Scala添加了continuations,让您可以构建生成器之类的东西。我认为这不太可能出现在Java中,事实上,这可能不是我想要的100%。我只想做一些事情时,螺旋 s、 我是空的。BlockingQueue是否可以轻松修改,使其在spirals.size>threshold时阻塞?因为我希望它在spirals.size>0时阻塞/等待。然后等待,直到调用next,然后再次生成下一个元素,依此类推。实际上,spirals.put将阻塞,直到主线程出现并调用spirals.take为止,因此一次只有一个值通过队列。如果你想对队列的大小有一个更大但仍然固定的限制,用一个你需要的任何容量的队列替换SynchronousQueue。啊,好的,SynchronousQueue确实是我需要的,我应该在询问之前阅读文档。