简体   繁体   English

Java执行程序模型,仅允许在实例化线程上运行任务

[英]Java executor model that allows running tasks only on instantiating thread

I am writing a multithreaded application where I've got the situation that I have certain library-related methods that can only be run on the main-thread . 我正在编写一个多线程应用程序,在这种情况下,我遇到了某些只能 main-thread 上运行的与库相关的方法。 Currently I am running a simple, self-written, solution that listens on a queue for tasks and then executes them serially as they come in. 目前,我正在运行一个简单的,自编写的解决方案,该解决方案在队列中侦听任务,然后在传入任务时依次执行它们。

This works so far although it gets ugly when I need return values etc. (Which I am currently solving the c-way by passing along datastructures with the tasks and then have a busy-loop checking if the structure has been written to on the site of the method that queues a task. 到目前为止,这仍然有效,尽管当我需要返回值等时很难看。(目前我正在通过传递带有任务的数据结构来解决c方式,然后进行忙循环检查该结构是否已在现场写入将任务排队的方法。

This is not really the cleanest solution, and while it works, I was hoping to find a better way of doing this.. 这确实不是最干净的解决方案,并且在可行的同时,我希望找到一种更好的方法。

Q : Is there anything in the JDK or in a single specialized library that does what I need? :JDK或单个专用库中是否有我需要的东西? Or is there any programming pattern that addresses my needs in a clean and structured way? 还是有任何一种编程模式可以干净整洁地满足我的需求?

A possible solution with CompletableFuture : 使用CompletableFuture的可能解决方案:

class Job<T> {
    private final Supplier<T> computation;
    private final CompletableFuture<T> future;

    Job(Supplier<T> computation, CompletableFuture<T> future) {
        this.future = future;
        this.computation = computation;
    }

    public Supplier<T> getComputation() {
        return computation;
    }

    public CompletableFuture<T> getFuture() {
        return future;
    }
}

public void client() {
    // on the client:
    CompletableFuture<String> future = new CompletableFuture<>();
    Supplier<String> computation = () -> "Here I am!";

    enqueue(new Job<>(computation, future));

    String resultString = future.get();
}

public <T> void server(Job<T> job) {
    // on the server; job is taken from the queue
    CompletableFuture<T> future = job.getFuture();
    future.complete(job.getComputation().get());
}

Here, on the client, future.get() will wait infinitely until the result is available. 在这里,在客户端上, future.get()将无限期等待直到结果可用。 There is also another form: 还有另一种形式:

future.get(1, TimeUnit.MINUTES)

would only wait for one minute and then return. 只会等待一分钟,然后返回。 This for can be used for polling. 可以用于轮询。

Let your main thread plays role of an Executor: 让您的主线程扮演执行者的角色:

static ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(10);
public static void main(String... args) {
    // initialization...
    for (;;) {
        queue.take().run();
    }
}

Whenever you need to execute a task on the main thread, put it to the queue: 每当需要在主线程上执行任务时,请将其放入队列:

 queue.add(()->methodCall(1,2,3));

I'm not sure how you are time-slicing the main thread, but what you are saying is that you want to run some jobs using multiple threads and other jobs on the main thread sequentially. 我不确定您如何对主线程进行时间切片,但是您要说的是要使用多个线程来运行某些作业,而要在主线程上依次运行其他作业。

Simplest answer would be to use two different work queues - one which is serviced by multiple threads and one which is serviced by only the main thread. 最简单的答案是使用两个不同的工作队列-一个由多个线程提供服务,一个仅由主线程提供服务。

This would make both queues easier to understand and use. 这将使两个队列更易于理解和使用。

Also, jobs running on either queue should implement an interface that requires them to expose a method that returns a reference to the resulting data - this might be the actual results or a file name or an input stream attached to the file containing the results. 同样,在任一队列上运行的作业都应实现一个接口,该接口要求它们公开返回对结果数据的引用的方法-这可能是实际结果,也可能是文件名或附加到包含结果的文件的输入流。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM