如何将Spring应用程序设置为单线程或使其具有一个实例?

时间:2017-09-01 21:33:29

标签: java spring thread-safety

我有一个Spring应用程序,它由一个我们需要单线程的API控制,但我无法弄清楚如何实现这一点。该应用程序是对单线程应用程序进行重新分解。他们想要新版本的相同基本设计,同时使用我们的新编程方法(即Java,Spring等)并添加额外的功能。

有一个API资源可以启动应用程序:

@RequestMapping("/start")
public String startProcess(){...}

如果调用两次,则应用程序将启动另一个线程。 我们希望阻止这种情况发生。但是,我们仍然希望停止API资源起作用:

@RequestMapping("/stop")
public String stopProcess(){...}

该应用程序具有典型的Spring结构:

@SpringBootApplication
public class MyApplication{...}

@RestController
public class MyController{   
    @Autowired
    private MyService myService;
    ...}

@Service
@Transactional
public class CarolService{
    @Autowired
    private MyDAO myDAO;
    ...}

@Repository
public class myDAO{...}

如何确保一次只运行此应用程序的一个实例?请帮忙!并且,提前谢谢!

1 个答案:

答案 0 :(得分:1)

实际上有两个不同的问题:使您的API成为单线程,并确保一次只运行此应用程序的一个实例。

解决方案在概念上是相同的:您必须在某些互斥锁上进行同步。但是在第一种情况下比在第二种情况下要容易得多。

要使您的API单线程,您需要同步某些内容。如果您只有一个控制器,只需制作API方法synchronized即可。如果您有多个控制器,则需要创建一些应用程序范围bean,将其注入每个控制器并在其上进行同步。在过去,也有类似SingleThreadModel的东西,但我认为它已被弃用。几年没有看过它,但如果Spring有办法以某种方式设置它,我不会感到惊讶。

确保一次只运行此应用程序的一个实例要困难得多。您基本上希望阻止任何人并行启动应用程序的多个副本。实现这一目标的方法之一是拥有一些中央共享资源,如数据库。在启动时,应用程序将尝试通过在某个表中创建记录来“获取”互斥锁(这将允许最多一条记录)。如果记录创建成功,则应用程序正常启动,否则则失败。您需要一些机制来检测陈旧的互斥记录 - 可能就像在互斥记录中保存时间戳并通过计划任务(心跳)不断更新它一样简单。

我们最近在运行许多微服务的许多实例的应用程序中有类似的任务。我们只需要一个微服务来定期执行某些维护任务。我们通过中央MongoDB数据库进行同步来解决它。微服务尝试通过在数据库集合中创建文档来获取互斥锁。通过设计,该集合中最多可存在一个文档,并且创建该文档的微服务执行常规任务并在最后移除该文档。该集合配置了自动清理,因此如果微服务因任何原因无法删除文档,它将被数据库自动删除。