通知()/等待()的Java问题
Posted
技术标签:
【中文标题】通知()/等待()的Java问题【英文标题】:Java issues with notify() / wait() 【发布时间】:2013-08-12 07:09:49 【问题描述】:我在Iterator
实例中有一个生成器,每次在迭代器上调用next()
时,它都会生成并返回一个项目。它似乎确实有效,但我得到了 null
值返回。
类代码:
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);
测试代码:
package spiral;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author Beheerder
*/
public class Spiral7DGeneratorTest
public Spiral7DGeneratorTest()
@Test
public void testHasNext()
@Test
public void testNext()
System.out.println("test");
Spiral7DGenerator s7dg = new Spiral7DGenerator();
System.out.println("s7dg.next() = " + s7dg.next());
System.out.println("s7dg.next() = " + s7dg.next());
System.out.println("s7dg.next() = " + s7dg.next());
System.out.println("s7dg.next() = " + s7dg.next());
@Test
public void testRemove()
测试输出:
test
s7dg.next() = null
s7dg.next() = null
s7dg.next() = null
s7dg.next() = null
恐怕这只是一件简单的事情,但我完全忽略了它。
【问题讨论】:
你真的需要写这么复杂的代码。对我来说,这很难读,也很难理解。我在阅读那些嵌套的 for 循环时内存不足。 @JunedAhsan 虽然问题本身与代码无关,但我可以解释为什么它如此复杂。那是因为一般来说制作螺旋很复杂,当然我更愿意让它通用而不是这个,但目前这对我来说太难了。 您在 Spiral7DGenerator() const 中的循环永远不会结束,并且在每次迭代时都会启动新线程。这是一个错误(因为内存有限) 使用多线程很少能简化代码。我仍然认为这更简单,更有可能工作***.com/questions/18074982/… 另一个答案***.com/questions/11570132/… 【参考方案1】:我还没有完全理解您的代码,但我可以提出两点:
releaseList
必须声明为 volatile
(至少),因为它是在同步块之外分配的。
您的next
方法不会等待通知线程唤醒并产生结果。这是一个竞争条件。您需要next
等待额外的互斥锁(或其他东西)以允许生成器通知releaseList
已设置。 (实际上,当您这样做时,您将不再需要使 releaseList
变为 volatile。)
【讨论】:
我怀疑是next()
根本不等待工作线程导致所有空值。你对releaseList
(和releaseNext
)也没有安全更新是完全正确的。【参考方案2】:
这里的想法是工作线程将结果流提供给主线程,对吗?
我建议你不要尝试手动构建并发控制逻辑,而是使用SynchronousQueue
。代码如下所示:
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
【讨论】:
谢谢!这正是我所需要的。虽然 Java 没有 Python 的yield
等价物,但真是太可惜了。
确实如此。当然,Scala 已经添加了可以让你构建诸如生成器之类的东西的延续。不过,我认为这不太可能出现在 Java 中。
实际上,这可能不是我想要的 100%。我希望generate()
只在spirals.isEmpty()
时做某事。 BlockingQueue
是否可以(轻松)修改为在spirals.size() > threshold
时阻塞?因为我希望它在spirals.size() > 0
时阻止/等待。然后等到next()
被调用,再生成下一个元素,以此类推
事实上,spirals.put
将阻塞直到主线程出现并调用spirals.take
,因此一次只会有一个值通过队列。如果您想对队列大小设置更大但仍然固定的限制,请将SynchronousQueue
替换为您需要的任何容量的ArrayBlockingQueue
。
啊,好吧,SynchronousQueue
确实正是我所需要的,我应该在询问之前阅读文档。以上是关于通知()/等待()的Java问题的主要内容,如果未能解决你的问题,请参考以下文章
Day826.Java多线程等待&通知机制 -Java 并发编程实战
Day826.Java多线程等待&通知机制 -Java 并发编程实战