我在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
我担心这只是一件简单的事情,但我完全忽略了它。
答案 0 :(得分:5)
我还没有完全理解你的代码,但我可以提出两点:
releaseList
必须声明volatile
(至少),因为它是在同步块之外分配的。next
方法不会等待通知的线程唤醒并产生结果。这是竞争条件。您需要next
等待额外的互斥锁(或其他内容)以允许生成器通知已设置releaseList
。 (实际上,当你这样做时,你不再需要让releaseList
变得更加易变。)答案 1 :(得分: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
}
}