Когда следует сказать, что операция началась?Когда это начинается, или когда это заканчивается? - PullRequest
0 голосов
/ 11 декабря 2018

Извините за странно сформулированный заголовок, но я столкнулся с интересной проблемой параллелизма в моем тестировании.Вот соответствующий код:

public class CancelableOperation {

     boolean canceled;
     boolean started;

     public void start() {
         if (!canceled) {
             started = true;
             // Kick off actual operation on another thread
         }
     }

     public void cancel() {
         if (!started) {
              canceled = true;
         } else {
              // Attempt to cancel the other operation
         }
     }
}

@Test
public void test() {
    CancelableOperation op = new CancelableOperation();
    op.start();

    while (!op.started) {
        Thread.sleep(5);
    }

    op.cancel();
}

Проблема заключается в том, что cancel() вызывается после started, равного true, но до того, как фактическая операция была запущена в новом потоке.На практике для «фактического» запуска операции требуется около 3 миллисекунд, но этого более чем достаточно для вызова cancel() в моем тесте.Я, конечно, могу поставить небольшой Thread.sleep() в тест (после того, как мы определили, что op.started верно), чтобы дождаться начала операции, но я бы вместо этого изменил свой код, чтобы справиться с этимкрайний случай.

Очевидно, что запуск операции во вторичном потоке является корнем проблемы, но, поскольку операция является длинным, синхронным процессом, перемещение его в этот поток не представляется возможным.Любая помощь будет оценена!

1 Ответ

0 голосов
/ 11 декабря 2018

Вы можете использовать CyclicBarrier

CyclicBarrier.CyclicBarrier - это синхронизатор, который позволяет ряду потоков ожидать друг друга для достижения общей точки выполнения, также называемой барьером.CyclicBarriers используются в программах, в которых у нас есть фиксированное количество потоков, которые должны ждать друг друга, чтобы достичь общей точки, прежде чем продолжить выполнение.

Так что этот код поможет вам:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

class CancelableOperation {

    boolean canceled;
    boolean started;
    public static final CyclicBarrier gate = new CyclicBarrier(2);

    public CancelableOperation() {
        gate.reset();
    }

    public void start() {
        if (!canceled) {
            System.out.println("started");
            started = true;
            try {
                gate.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
            // Kick off actual operation on another thread
        }
    }

    public void cancel() {
        try {
            gate.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
        if (!started) {
            System.out.println("canceled");
            canceled = true;
        } else {
            // Attempt to cancel the other operation
        }
    }
}

public class Test {
    public static void main(String[] args) {
        CancelableOperation op = new CancelableOperation();
        new Thread(op::start).start();
        new Thread(op::cancel).start();

    }
}

Так что, если cancel() достигнет gate.await();, он заблокируется, пока не достигнет start(), чтобы запустить другую нить

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...