Как обеспечить выполнение одноэлементного (одного глобального экземпляра) ScheduledExecutorService, по одной задаче за раз? - PullRequest
0 голосов
/ 27 января 2019

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

Для однократных запросов я просто использую поток, подобный следующему:

    public void request() {
        Thread requestThread = new Thread(this);
        requestThread.start();
    }

Все в порядке, они выполняются, а затем все готово.

Тем не менее, для длинных задач опроса, я никогда не могу выполнить только одну из них одновременно.

Я хочу, чтобы следующий метод:

    public void longPoll() {
        try {
            pollingScheduledExecutor.scheduleAtFixedRate(this, 0, 3, TimeUnit.SECONDS);
        } catch (Exception ignored) {
        }
    }

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

Как обеспечить, чтобы существовал только один глобальный экземпляр этого ScheduledExecutorService?

Для контекста, здесь класс, в котором живут эти методы:

public abstract class AbstractCommunicationChannel implements Runnable {
    static String SERVER_ADDRESS = "http://0.0.0.0";

    private URL url;
    private JSONObject requestObject;
    private JSONObject responseObject;

    private volatile ScheduledExecutorService pollingScheduledExecutor = Executors.newSingleThreadScheduledExecutor();

    public void longPoll() {
        try {
            pollingScheduledExecutor.scheduleAtFixedRate(this, 0, 3, TimeUnit.SECONDS);
        } catch (Exception ignored) {
        }
    }

    public void request() {
        Thread requestThread = new Thread(this);
        requestThread.start();
    }

    AbstractCommunicationChannel(URL url, JSONObject requestObject) {
        this.url = url;
        this.requestObject = requestObject;
    }

    /**
     * This is the general purpose tool for hitting the server and getting a response back.
     */
    public void run() {
        Log.i("requestObject", requestObject.toString());
        try {
            HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
            httpUrlConnection.setDoOutput(true);
            httpUrlConnection.setRequestMethod("POST");
            httpUrlConnection.setRequestProperty("Content-Type", "application/json; charset=utf-8");

            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(httpUrlConnection.getOutputStream());
            outputStreamWriter.write(requestObject.toString());
            outputStreamWriter.flush();
            outputStreamWriter.close();
            /* * */
            InputStream inputStream = httpUrlConnection.getInputStream();
            BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            int result = bufferedInputStream.read();
            while (result != -1) {
                byteArrayOutputStream.write((byte) result);
                result = bufferedInputStream.read();
            }
            responseObject = new JSONObject(byteArrayOutputStream.toString("UTF-8"));
            httpUrlConnection.disconnect();
        } catch (Exception ignored) {
        }
        processResponse(responseObject);
    }

    protected abstract void processResponse(JSONObject responseObject);
}

1 Ответ

0 голосов
/ 27 января 2019

это снова я.

Если вам нужна только одна запущенная задача опроса, вы должны отменить предыдущую, если она уже существует.

Пример:

private static final Object lock = new Object();
private static ScheduledFuture<?> currentRunningTask;

    public void longPoll() {

        synchronized (lock) {

            if (currentRunningTask != null) {
                currentRunningTask.cancel(true);
            }

            try {
                currentRunningTask = pollingScheduledExecutor.scheduleAtFixedRate(this, 0, 3, TimeUnit.SECONDS);
            } catch (Exception ignored) {
                ignored.printStackTrace();
            }
        }
    }
...