C#2.0のyield return/yield breakに触発されて継続によるイテレータを実装してみました。上のクラスがイテレータで、下のクラスが利用クラスです。
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
public abstract class ContinuationIterator<T> implements Iterator<T>,
Iterable<T> {
private class Entry {
private boolean eof;
private T value;
Entry(T value, boolean eof) {
this.value = value;
this.eof = eof;
}
T getValue() {
return this.value;
}
boolean isEof() {
return this.eof;
}
}
private static final String THREAD_NAME_BASE = ContinuationIterator.class
.getSimpleName();
private static int threadId = 0;
private static ExecutorService workerPool = Executors
.newCachedThreadPool(new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r,
ContinuationIterator.THREAD_NAME_BASE + "-"
+ (ContinuationIterator.threadId++));
t.setDaemon(true);
return t;
}
});
private boolean async;
private Entry current;
private LinkedList<Entry> list;
private boolean readed = false;
private boolean started = false;
public ContinuationIterator() {
this.list = new LinkedList<Entry>();
this.async = true;
}
public ContinuationIterator(boolean async) {
this.list = new LinkedList<Entry>();
this.async = async;
}
public final boolean hasNext() {
if (this.current == null) {
this.processQueue();
} else if (this.readed) {
this.processQueue();
}
this.readed = true;
return !this.current.isEof();
}
public Iterator<T> iterator() {
return this;
}
public final T next() {
if (!this.readed) {
this.processQueue();
}
if (this.current.isEof()) {
throw new NoSuchElementException();
}
return this.current.getValue();
}
protected abstract void process();
private void processQueue() {
synchronized (this.list) {
if (!this.started) {
this.started = true;
ContinuationIterator.workerPool.submit(new Runnable() {
public void run() {
ContinuationIterator.this.process();
ContinuationIterator.this.yieldBreak();
}
});
}
while (this.list.isEmpty()) {
try {
this.list.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
this.readed = false;
this.current = this.list.removeFirst();
this.list.notifyAll();
}
}
private void pushQueue(T value, boolean eof) {
synchronized (this.list) {
Entry entry = new Entry(value, eof);
if (!this.async) {
while (!this.list.isEmpty()) {
try {
this.list.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
this.list.addLast(entry);
this.list.notifyAll();
}
}
public void remove() {
throw new UnsupportedOperationException();
}
protected final void yieldBreak() {
pushQueue(null, true);
}
protected final void yieldReturn(T value) {
pushQueue(value, false);
}
}
public class Sample{
public static void main(String[] args){
ContinuationIterator<Integer> iterator1 = new ContinuationIterator<Integer>(){
protected void process(){
for(int i = 0; i < 10; i++){
this.yieldReturn(i);
}
}
}
for(int i: iterator1){
System.out.println(i);
}
ContinuationIterator<Integer> iterator2 = new ContinuationIterator<Integer>(){
protected void process(){
for(int i = 0; i < 10; i++){
if(i == 5){
this.yieldBreak();
}
this.yieldReturn(i);
try{
Thread.sleep(100);
}catch(InterruptedException e){
}
}
}
}
for(int i: iterator2){
System.out.println(i);
}
}
}
動作原理はイテレータを内部で別スレッドにしてキューに追加しています。それがyieldReturn()とyieldBreak()メソッドになります。利用側はイテレータインターフェイスを通じてキューから取得するようになっている感じです。
この仕組みは結構コードがシンプルにかけていいですね。