澄清多线程和竞争条件

问题描述 投票:0回答:1

假设我有两个API:

获取客户姓名 另一个用于更新客户名称

我同时有两个更新客户名称的请求, 如何自动处理这种并发并且不发生竞争条件?

因为我没有看到任何现实世界的例子在这种情况下使用同步。

你能帮我解释一下吗?

@RestController
@RequestMapping("/api/customers")
public class CustomerController {

    @Autowired
    private CustomerService customerService;

    @GetMapping("/{id}")
    public String getCustomerName(@PathVariable Long id) {
        return customerService.getCustomerName(id);
    }

    @PutMapping("/{id}")
    public String updateCustomerName(
            @PathVariable Long id,
            @RequestParam String name,
            @RequestParam int version) {
        return customerService.updateCustomerName(id, name, version);
    }
}

java multithreading synchronized
1个回答
0
投票

这里没有竞争条件。 update 会做一些事情,get 会看到或看不到它。因为这两个调用之间没有关系,所以不需要遵守某些顺序。

customerService
类可能无法处理使用与另一个线程中当前并发运行的
getCustomerName(id)
调用相同的id调用其
updateCustomerName(thatId)
方法,在这种情况下,您需要提出一个不同的问题,其中包括代码。

出现多核问题的地方例如是这样的问题:

  • 其他位置的 API 用户首先连接到我的 Web 服务并运行
    PUT /1234
    ,将客户名称更新为
    newName
    。该客户等待该调用完成,然后再次连接到我的 API,这次发送 HTTP 请求
    GET /1234
    。我想告诉该用户,我们保证他们观察到的状态至少与他们的更新一样新,即如果名称之前是
    oldName
    ,我们绝对不会将其发回。

仅基于您粘贴的代码,您可以提供该保证。提供这些保证的方法几乎总是归结为数据库:它根本与 java 代码无关:您不需要

synchronized
或任何其他并发原语。相反,正确设置数据库并正确使用事务。

如果你想仅用这个java代码提供保证,你必须确保

getCustomerName
行和
updateCustomerName
行都位于
synchronized(x)
块内,其中
x
指向同一个对象。您可以为此使用
this
(即将两种方法标记为
synchronized
)。但这通常不是您做这样的事情的方式,并且通常数据库对锁定提供更细粒度的控制;例如,DB可以进行乐观锁定; java的同步原语不允许这样做;你必须使用java的CAS(比较和设置,用于乐观锁定的通用机制)系统,对于你在这里做的事情来说,它比数据库事务更难使用。

© www.soinside.com 2019 - 2024. All rights reserved.