Answer the question
In order to leave comments, you need to log in
How to ensure performance in a multi-threaded environment?
Good afternoon.
There is the following problem. There is a service class OrderService . It has a create(Order order, Long companyId) method , which checks if the order amount does not exceed the company's balance before creating an order. The class code is something like the following.
public class OrderService {
public Order create(Order order, Long companyId) {
Company company = companyService.get(companyId);
checkCompanyBalance(company.getBalance(), order.getSum());
return create(order);
}
}
public class CompanyPool {
private Set<Long> companyIds = new HashSet<Long>();
public synchronized containsAndPut(Long companyId) {
if(companyIds.contains(companyId)) {
return false;
} else {
companyIds.add(companyId);
return true;
}
}
public synchronized remove(Long companyId) {
companyIds.remove(companyId);
}
}
public class OrderService {
private CompanyPool companyPool = new CompanyPool();
public Order create(Order order, Long companyId) {
if(companyPool.containsAndPut(companyId)) {
Company company = companyService.get(companyId);
checkCompanyBalance(company.getBalance(), order.getSum());
Order newOrder = create(order);
companyPool.remove(companyId);
return newOrder;
} else {
// wait till other thread will stop creating order for specified company
}
}
Answer the question
In order to leave comments, you need to log in
As correctly noted above, it is not very clear why the company's balance sheet data is stored exclusively in memory. This kind of information must be persistent.
In essence, your problem: you just need to start a separate lock for each company. To be sure to have exactly one lock, use ConcurrentMap#putIfAbsent .
In general, you should not do something that you do not understand in any way. Read something first. I recommend Java Concurrency in Practice .
> But at the same time, productivity sags a lot, because there is no way to create an order for another company.
I do not believe. Do you have a 100 million audience?
Use DBMS. This is only the first rake that you start stepping on. Your solution will misbehave if the program crashes. It may turn out that the money is written off, but the order is not remembered, or vice versa. Moreover, you need a DBMS with transaction support, the now fashionable noSQL solutions will not work, or you will write your own transactional engine on top of them (there is an example in the documentation for mongodb).
Well, or, if you really want to, you need to rewrite
checkCompanyBalance(company.getBalance(), order.getSum());
so that it enters the critical section (captures the mutex belonging to the company object), checks the balance, if there is enough money, subtracts the amount from the balance, writes a message to the transaction list, for which money was debited, and then writes all this information into non-volatile, multi-machine-reserved memory, and finally released the mutex. Then we create an order, write it to the same reliable storage. And, after that, we again climb into the company object and mark the transaction as completed.
you can make synchronized by company… but this is if there is only one instance for each company…
I completely agree with comrade gvsmirnov.
However, it seems to me that performance sags due to an overhead on the scheduler, if the thread fails to take the lock. Therefore, it seems to me that there is a place to be a spinlock based on AtomicBoolean
.
public class OrderService {
private AtomicBoolean locked = new AtomicBoolean(false);
public Order create(Order order, Long companyId) {
Order result;
// Пробовать зайти в крит. секцию.
while (!locked.compareAndSet(false, true)) {
Company company = companyService.get(companyId);
checkCompanyBalance(company.getBalance(), order.getSum());
result = create(order);
// Открыть путь другим потокам.
locked.set(false);
break;
}
return result;
}
}
checkCompanyBalance
and create
are executed quickly . Otherwise, your code will just wait for the lock to be released, wasting CPU cycles completely incompetently.Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question