Итак, я разрабатываю многопоточную систему, которая отправляет команды (шаблон разработки команд) от клиента к серверу, и там они выполняются java.util.concurrent.newCachedThreadPool
, а ответ отправляется обратно с использованием UDP.
Внутри этой команды мне нужно обработать некоторые запросы к базе данных и изменения в локальной java.util.HashMap
коллекции. Вся синхронизация должна производиться с использованием java.util.concurrent.locks.ReentrantLock
.
Запросы простые, INSERT, DELETE, UPDATE, с использованием идентификатора автоинкремента и обычных данных. Для транзакций я использую java.sql.PreparedState
и обычный java.sql.Connection
шаблон фиксации, et c.
Для связи с базой данных у меня есть 3 класса:
- UserModel, имеет все запросы, связанные с управлением пользователями
- CollectionModel, все запросы, относящиеся к коллекции
- CollectionController, имеет экземпляр моделей и вызывает их методы, чтобы упростить задачу команды для выполнения вызовов и изменений db.
И в зависимости от результата запросов я меняю локальную коллекцию. Теперь мои вопросы следующие:
- Как реализовать ReentrantLock для синхронизации изменений, сделанных в локальной коллекции.
- ReentrantLock должен быть реализован на уровне CollectionController или должна быть блокировка внутри каждой модели
- Действительно ли необходимо реализовать синхронизированную среду для вызова и изменений базы данных? Важно отметить, что я использую шаблон транзакции для каждого запроса.
- Как будет реализована блокировка на уровне моделей?
- Я открыт для изменений в структуре проект, чтобы сделать его более solid на многопоточном. В специальной части Executor я не совсем уверен, правильно ли это реализовать.
CollectionManager. java, home of В локальной коллекции методы вызываются в зависимости от команды и ее метода execute ().
public class CollectionManager {
private HashMap<Integer, Dragon> collection = new HashMap<Integer, Dragon>;
public void clear() {
this.getCollection().clear();
}
/**
* Функция сортировки коллекции
* @return возвращает отсортированную по ID коллекцию
*/
public List<ListEntrySerializable> sortById()
{
return this.getCollection()
.entrySet()
.stream()
.sorted(Comparator.comparing(x -> x.getValue().getId()))
.map(e -> new ListEntrySerializable(e.getKey(), e.getValue()))
.collect(Collectors.toList());
}
public Object insert(Integer key, Dragon newDragon) {
return this.getCollection().putIfAbsent(key, newDragon);
}
public Object update(Integer id, Dragon newDragon)
{
Optional<Map.Entry<Integer, Dragon>> oldDragonKey =
this.getCollection()
.entrySet()
.stream()
.filter(dragonEntry -> dragonEntry.getValue().getId().equals(id))
.findFirst();
if (oldDragonKey.isPresent())
newDragon.setId(id);
return oldDragonKey.map(integerDragonEntry ->
this.getCollection().replace(integerDragonEntry.getKey(), newDragon)).orElse(null);
}
public Object removeKey(Integer key){
return this.getCollection().remove(key);
}
Метод-исполнитель для выполнения команды отправляет каждый ответ с сервера
private void executeObj(Object obj, SocketAddress addressFromClient) {
Future<Object> resulted = executor.submit(() -> {
Object responseExecution;
if (obj instanceof String)
responseExecution = obj;
else {
AbsCommand command = ((CommandPacket) obj).getCommand();
Credentials credentials = ((CommandPacket) obj).getCredentials();
try {
responseExecution = command.execute(executionContext, credentials);
}catch (Exception ex) {
responseExecution = ex.getMessage();
LOG.error(ex.getMessage(), ex);
}
}
socket.sendResponse(responseExecution, addressFromClient);
return responseExecution;
});
//....method to print the future object (not important)
}