由jar文件创建的多线程在关闭jar文件后继续运行



嗨,伙计们,我刚拿起春靴,想听听一些建议!

我需要创建一个可以从一个位置移动到另一个位置的对象,通过数学计算的增量。一旦"start"rest调用被执行,它就会在2 - 3个预先指定的点之间永远巡逻(为此,我实现了一个无限while循环,在开始rest调用时将条件设置为true,在结束rest调用时将条件设置为false),直到"stop"rest调用被调用。

这个rest调用同时也创建了多达20个对象,因为有一个无限while循环,我不能只做一个for循环来创建20个这样的对象,它将被卡住在第一次迭代是一个阻塞代码,由于无限while循环。

为了解决这个问题,我使用了java线程,这样我就可以并发地创建任意数量的这些对象。由于thread.stop()已被弃用,我使用了类似service. setisthreadrunning (false)的东西作为我的控制器和服务层

我在run()方法中使用了一个while(isThreadRunning)。

已经尝试使用中断的方式来关闭线程,但它似乎不成功完全关闭它,对我来说有效的方法是使用全局变量。

其中isThreadRunning是一个全局变量,一旦调用end rest调用就被设置为false。

根据我的理解,全局变量甚至在不同的线程之间是共享的,所以通过改变这个全局变量,stop方法对我来说没有问题。

所有这些在本地工作没有问题。

当我试图在jar文件中部署这个spring引导应用程序时,主要问题出现了,其中有一个错误,关闭jar应用程序仍然会导致创建的线程继续运行。尽管多次调用end rest调用

根据我的搜索,似乎一个关机钩子,设置已创建的守护进程为true可能会修复它。如果可能的话,有没有其他的解释来解释为什么会这样?是否有一个独特的交互线程与jar文件,我没有考虑?

我的猜测是,这是由某人在关闭jar文件之前没有执行end rest调用引起的,然后当它再次启动时,它将位于新的内存位置,因此任何新的"end rest调用"将无法到达它。

对于一个修复,我已经尝试添加一个关闭钩子来设置变量为false,以防有人忘记做end rest调用,并设置创建的守护线程为true。

我理解在java中不建议使用无限while循环,但我真诚地愿意接受有关替代方法的建议,以满足这些要求。对于其他方法,我尝试过spring响应式编程(Mono, flux)架构(似乎卡在无限while循环中),@Async.

如果有人能给我一个方向,我可以看看如何处理这个问题,我会非常感激!

代码看起来像这样的线程实现:服务层:

public class Service extends Thread{
//global variable
@Setter
private boolean isThreadRunning=false;


@Override
public void run(){
while(isThreadRunning){
try{
moveObject();
}
catch{
log.error("ending movement");
}    
}
}

注*这是一个伪版本的代码,因为我不能复制粘贴它,我从scratch和内存中输入了这个,所以一些部分,如数学部分,这不是主要问题,我不会写太多细节。所有需要知道的数学部分是,新位置将被增加,并每3秒发送到前端以"移动"。对象。因此,无限while循环和对象应该无限移动,直到执行end rest调用。

问题无限while循环,因为我不允许复制代码,这是它的一般结构:

//pos consists of latitude, longitude 
public void moveObject() throws InterruptedException{
MovingObject obj = new MovingObject();
while(isThreadRunning){
for(int i =0;i<=iterations;i++){
if(isThreadRunning== false){
return;
}
else{
MathNewIncrementedPos();
}
}
}

}

控制器:

@Log4j2
@RestController
@RequiredArgsConstructor
@RequestMapping("/test")
public class Controller{
private final Service service;
ArrayList<Thread> threadList = new ArrayList<Thread>();
@PostMapping("/moveObject")
public void move(@PathVariable Integer noOfObj) throws InterruptedException{
for(int i=0;i<noOfobj;i++){
Thread newThread = new Thread(service);
newThread.setDaemon(true);
newThread.start();
threadList.add(newThread);
threadList.get(i).start();
}
}
@PostMapping("/endMovement")
public void endMove() throws InterruptedExecption{
int size = threadList.size();
service.setisThreadRunning(false);
//i dont think this is needed, but i just do it to try ensure all 
//threads are closed
for(int i=0;i<size;i++){
service.setisThreadRunning(false);
}
threadList.clear();
}
}
最后,一个shutdown钩子,以确保即使end rest调用没有被执行,所有线程都应该在关闭

之前关闭。
@PreDestroy
public void onExit(){
service.setisThreadRunning(false);
}

这在spring响应式编程中是可能的吗?(使用Mono/flux),因为我不确定如何以反应的方式包装这个。

嗨,只是在部署和测试我的代码后更新,关闭钩子的实现和设置守护进程解决了线程运行的问题,尽管通过cmd/按x关闭jar文件。我仍然在寻找Executor服务作为更好地封装我的代码的替代方法,但它仍然很难掌握它的概念。如果有一个实现它的例子,那就太棒了!

最新更新