我已经仔细考虑了一段时间了,随着时间的推移,我对线程、执行器等的了解也越来越多。我对执行器和线程有一个粗略的了解,但是我觉得有点卡住了。
这就是我想做的。
有命令,也有行动。例如,命令是命名的,用户可以任意调用它!播放歌曲!欢呼等。一个行动是把工作送到一个服务机构的东西;例如,请求websocket客户端发送一条新消息,或者请求irc客户端发送一条新消息,等等。
当一个命令被执行时,它一个接一个地按顺序执行它的动作。
例如,the!cheer命令可能有四个操作:
发出websocket请求,并等待成功响应(例如:在obs中显示场景项)
发送irc信息(例如:发送聊天信息)。一旦发送出去,
等待1-3秒(例如:等待视频结束播放)。一旦等待结束,那么
发出另一个websocket请求(例如:从步骤1隐藏场景项)
它们不仅必须按顺序执行,而且我们也不能让它们同时开始(操作1、2和4首先完成,然后操作3最后完成);每个动作都取决于它的前一个动作先完成。
除此之外,客户机可以随时任意提交命令,并且不能相互阻塞。例如!longcommand可以启动,但不会阻塞!启动shortcommand(假设底层服务没有被阻塞)。
我想做的是:
我知道我可以使用future/callable来阻止挂起在给定线程上执行的结果,因此每个操作在运行时都应该返回future(future来自它使用的相应服务)。然后,我可以简单地在一个命令上以这样的阻塞方式逐个调用这些操作,以确保它们按顺序执行,并且每个操作都等待另一个操作完成:
class ExecutableCommand implments Runnable {
// omitted for brevity
run() {
for(Action action:command.getActions()) {
action.run().get();
}
}
但是我该如何处理执行命令呢?我想我应该通过一个执行器来提交每个命令,或者像这样的线程池执行器来提交每个命令?
class ExecutorServiceWrapper {
private final ExecutorService executorService = Executors.newThreadPoolExecutor(4);
void submit(ExecutableCommand command) {
executorService.submit(command)
}
}
然后,每个客户端ofc只需保留对executorservicewrapper的引用,并调用它以响应触发它们的事件:
class FromChatHandler() {
private final ExecutorServiceWrapper masterQueue;
onMessage(String message) {
Command command = // parse what command to lookup from message
masterQueue.submit(command)
}
}
@RestController // or whatever
class MyController() {
private final ExecutorServiceWrapper masterQueue;
@Post
executeCommandByName(String commandName) {
Command command = // lookup command
masterQueue.submit(command)
}
}
class directHandler() {
private final ExecutorServiceWrapper masterQueue;
handle(Command command) {
Command command = // build the command given the message
masterQueue.submit(command)
}
}
我假设由于每个命令都被提交给执行器,所以每个命令都将进入自己的线程,这样它就不会阻塞其他的线程。
但我不确定我是否应该像上面那样使用executablecommand执行命令中的每个操作。
另外,我不确定它是否能处理这种情况:线程池固定为5个线程。已执行5个命令。它们运行时间很长,使用不同的服务,但是底层服务没有被阻塞,仍然可以接受工作。有人试图执行第6个命令——不应该阻止它们,因为底层服务仍然可以接受工作。
有没有更好的办法?我走对了吗?
1条答案
按热度按时间j8ag8udp1#
在这方面花了一点时间之后,我提出了一些可能的解决方案,可以使用执行者,也可以使用期货。现在还不确定哪一个会比另一个更好,但是因为我知道我可以扩展threadpoolexecutor(比如说,添加一个暂停特性),我可能会倾向于executors。
否则,如果任何人有意见,他们总是欢迎!
我现在把这两种解决方案都放在我的gh()中,但我也会把它们放在下面。https://github.com/tinatiel/concurrency-learning
期货执行
结果
输出和调度与预期一样,但似乎使用forkjoinpool。
执行人执行
结果
输出和进度如预期