Листинг 1.
Пример цикла, использующего внешнюю по отноше-
нии к нему переменную и генерирующего исключение, приведен ни-
же:
int someVar;
// Распараллеливаемый цикл
for (int i = 0; i < n; i++) {
throwingOperation();
someVar = someOp();
}
Этот код с применением предлагаемого метода может быть распа-
раллелен способом, показанным в листинге 2. В качестве временн ´ой
метки используется номер итерации цикла, а вместо проверки события
исключения — сравнение объекта исключения с null.
Листинг 2.
Распараллеленный цикл с обработкой исключения без
дополнительных оптимизаций:
int someVar;
// Объект синхронизации
final Object syncObj = new Object();
// Номер итерации, на которой сгенерировано исключение
volatile int iterExcNo = -1;
// Объект исключения
volatile Throwable loopThr = null;
// Список “номер итерации/записанный элемент”
ConcurrentLinkedQueue<Pair<int, int» someVarWrites = new
ConcurrentLinkedQueue<Pair<int, int»( );
volatile int lastWrite;
// Запускаем потоки или применяем задачу для существующего пула
for (int j = 0; j
<
nThreads; j++) {
new Thread(new Runnable() {
public void run() {
try {
// Разделeнный на итерации цикл
for (int i = j*nThreads; i
<
j*(nThreads + 1); i++) {
throwingOperation();
int value = someOp();
someVarWrites.add(new Pair
<
int, int
>
(i, value);
if (isLastWrite())
lastWrite = value;
}
}catch (Throwable thr) {
synchronized (syncObj) {
iterExcNo = i;
loopThr = thr;
}
}
}
}).start();
}
// Дождаться завершения потоков...
ISSN 0236-3933. Вестник МГТУ им. Н.Э. Баумана. Сер. “Приборостроение”. 2014. № 6 77