诀窍是让堆栈跟踪知道这两个方法中的哪一个正在调用 iterator.next 方法。
只要两个调用者都没有调用 next(),你就阻止前面的调用者。
- 这不是优化的。
- 我试图让这段代码线程安全,但因为我写得很快,一些同步问题可能仍然存在。我让你复习一下;)
- 我让你删除很多 System.out.println
originalIterator 基于 List,但使用您希望的数据结构。如您所见,stream.iterrator() 只被调用一次。
public static class InterleavingIterator<E> implements Iterator<E> {
private boolean hasNext;
private E next;
private final Iterator<E> originalIterator;
private final Map<String, Integer> stepCaller = Collections.synchronizedMap(new HashMap<String, Integer>());
private final AtomicInteger curStep = new AtomicInteger(0);
public InterleavingIterator(Iterator<E> originalIterator, String caller1, String caller2) {
this.originalIterator = originalIterator;
stepCaller.put(caller1, 0);
stepCaller.put(caller2, 0);
hasNext = originalIterator.hasNext();
}
public boolean hasNext() {
return hasNext;
}
public E next() {
String caller = getCurrentCaller();
int currentStep = curStep.get();
System.out.println("caller is " + caller);
if (stepCaller.get(caller) == currentStep) {
System.out.println("Caller " + caller + " is on current step. We need to move on.");
// we should go on next step. But first check that all caller are done with this step.
while (otherCallerBehind(currentStep)) {
System.out.println("Other caller are behind. Waiting for them...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("Ok, everybody is on current step. Going on.");
synchronized (curStep) {
if (currentStep == curStep.get()) {
// ok, go on.
curStep.incrementAndGet();
next = hasNext ? originalIterator.next() : null;
hasNext = originalIterator.hasNext();
System.out.println("hasNext=" + hasNext + ", next=" + next + ", currentStep=" + curStep.get());
}
}
}
E next2 = next;
stepCaller.put(caller, stepCaller.get(caller) + 1);
System.out.println("Caller " + caller + " is now at step " + stepCaller.get(caller) + ". Returning already fetch next : "
+ next);
return next2;
}
private boolean otherCallerBehind(int currentStep) {
for (Integer step : stepCaller.values()) {
if (step < currentStep) {
return true;
}
}
return false;
}
public void remove() {
throw new RuntimeException("Method remove not supported");
}
public String getCurrentCaller() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
// System.out.println(stackTraceElements[3].getMethodName());
return stackTraceElements[3].getMethodName();
}
}
public static void main(String[] args) {
List<Integer> stream = Arrays.asList(1, 2, 3, 4, 5);
final InterleavingIterator<Integer> interleavingIterator = new InterleavingIterator<Integer>(stream.iterator(), "f", "g");
final AtomicInteger fres = new AtomicInteger(-1);
final AtomicInteger gres = new AtomicInteger(-1);
new Thread() {
@Override
public void run() {
fres.set(f(interleavingIterator));
};
}.start();
new Thread() {
@Override
public void run() {
gres.set(g(interleavingIterator));
};
}.start();
while (fres.get() == -1 && gres.get() == -1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(fres);
System.out.println(gres);
}
public static Integer f(Iterator<Integer> i) {
Integer sum = 0;
while (i.hasNext()) {
sum += i.next();
}
return sum;
}
public static Integer g(Iterator<Integer> i) {
Integer prod = 1;
while (i.hasNext()) {
prod *= i.next();
}
return prod;
}