Как использовать ExecuteService с пользовательскими потоками, которые содержат ресурс AutoCloseable - PullRequest
1 голос
/ 13 мая 2019

Я представляю здесь упрощение проблемы, которую пытаюсь решить. Резюме классов, которые я представляю:

  • Процессор: это не поточно-безопасный класс, который может быть создан без каких-либо аргументов и должен быть закрыт, когда вы закончите его использовать. Создание экземпляров этого класса действительно дорого, поэтому должен быть создан только один (на поток). Предоставляет методы для выполнения определенных операций.
  • ResultProvider: потокобезопасный класс, который управляет запросами, для которых требуется обработчик.

Текущая реализация похожа на следующую:

class Processor implements AutoCloseable { (...) }

class ResultProvider implements AutoCloseable {

    private final Processor processor;

    public ResultProvider() {
        this.processor = Processor.createNewProcessor();
    }

    /*
     * The 'request' doesn't turn a Procesoor into a T, it rather uses a Processor
     * as a resource, to be able to compute a T
     */
    public synchronized <T> T handle(Function<Processor, T> request) {
        request.apply(processor);
    }

    public synchronized void close() {
        processor.close();
    }
}

Теперь я хочу, чтобы ResultProvider мог использовать несколько процессорных ядер. В идеале я хотел бы иметь возможность использовать ExecutorService для этого. Обратите внимание, что каждый Поток должен создавать свой собственный Процессор при запуске и должен .close () его, когда Поток должен быть удален. ExecutorService, вероятно, должен использовать ThreadFactory, который создает пользовательский подкласс Thread, который создает и закрывает внутренний процессор.

Я думаю, что я хотел бы что-то вроде этого:

class ResultProvider implements AutoCloseable {

    private static class ProcessorThread extends Thread {
        final private Processor processor = Processor.createNewProcessor();

        public void run() {
            try {
                super.run();
            } finally {
                processor.close();
            }
        }
    }

    private final ExecutorService executor;
    /*
     * Not sure how to create one that uses my ProcessorThread and is able
     * to be submitted Function<Processor, T> to get T...
     */

    public ResultProvider() {
        // ...
    }

    /*
     * The 'request' doesn't turn a Procesoor into a T, it rather uses a Processor
     * as a resource, to be able to compute a T
     */
    public <T> T handle(Function<Processor, T> request) {
        return executor.submit?(request).get();
    }

    public synchronized void close() {
        executor.shutdown();
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
    }
}

Теперь, возможно ли это? Я не знаю, как реализовать это, используя как можно больше параллельных классов Java. Любой совет?

1 Ответ

2 голосов
/ 13 мая 2019

Вам не нужно никаких пользовательских потоков.Все, что вам нужно, это создать и отправить Callable, который создает процессор, вызывает функцию и закрывает процессор:

public <T> T handle(Function<Processor, T> request) {
    Callable<T> callable = () -> {
        try(Processor processor = Processor.createNewProcessor()) {
            request.apply(processor);
        } 
    }
    return executor.submit(callable).get();
}

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

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

...