简体   繁体   English

Java问题与notify()/ wait()

[英]Java issues with notify() / wait()

I have a generator inside an Iterator instance, which generates and returns one item every time next() is called on the iterator. 我在Iterator实例中有一个生成Iterator ,每次在迭代器上调用next()时,该生成Iterator生成并返回一项。 It does seem to kind of work, but I am getting null values returned. 它似乎确实可以工作,但是我返回的是null值。

Class code: 班级代码:

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);
        }
    }
}

Testing code: 测试代码:

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 output: 测试输出:

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

I'm afraid it is just a simple thing, but I am overlooking it completely. 恐怕这只是一件简单的事情,但是我完全忽略了它。

I haven't fully understood your code but two points I can make: 我还没有完全理解您的代码,但是我可以指出两点:

  • releaseList must be declared volatile (at least) as it is being assigned outside a synchronized block. 必须将releaseList声明为volatile (至少),因为它是在同步块外部分配的。
  • your next method does not wait for the notified thread to wake up and produce a result. 您的next方法不等待通知的线程唤醒并产生结果。 This is a race condition. 这是比赛条件。 You need next to wait on an extra mutex (or something) to allow the generator to notify that releaseList has been set. next ,您需要等待额外的互斥锁(或某些互斥对象),以允许生成器通知已设置releaseList (Actually, when you do this, you won't need to make releaseList volatile any more.) (实际上,执行此操作时,无需再使releaseList变得易变。)

The idea here is that the worker thread feeds a stream of results to the main thread, correct? 这里的想法是工作线程将结果流馈送到主线程,对吗?

I suggest that you do not attempt to construct the concurrency control logic by hand, but instead use a SynchronousQueue . 我建议您不要尝试手动构造并发控制逻辑,而应使用SynchronousQueue The code would look like: 代码如下所示:

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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM