Пружинная загрузка: ReentrantLock - PullRequest
0 голосов
/ 10 марта 2020

Я закодировал @Repository класс:

@Repository
public class RepositoryDocumentDao {

    private static final Logger LOG = LoggerFactory.getLogger(RepositoryDocumentDao.class);
    private ReentrantLock lock;

    @Autowired
    public RepositoryDocumentDao(
    ) {
        this.lock = new ReentrantLock();
    }
}

Мой связанный код:

private boolean verifyStorageSize(long requiredBytes) {
    this.lock.lock();
    LOG.debug("IN");
    //.. do someting large
    LOG.debug("OUT");
    this.lock.unlock();
}

Я просмотрел журналы, и в него вошли две темы защищенный код:

http-nio-8080-exec-3 =================IN=================  
...
http-nio-8080-exec-10 =================IN================= 

Есть идеи?

1 Ответ

0 голосов
/ 10 марта 2020

Я не смог воспроизвести случай, который вы упомянули , но я привел вам простой пример того, как я реализовал код.

    @RestController
    @RequestMapping("/event")
    public class EventRestController extends BaseRestController {

        private final EventService service;

        @Autowired
        public EventRestController(final EventService service) {
            this.service = requireNonNull(service, "service can't be null");
        }

        @PutMapping(value = "/sync")
        public Callable<ResponseEntity<Void>> syncOperation() {
            return () -> service.syncOperation();
        }
    ...
    }

    @Service
    @Slf4j
    public class EventServiceImpl implements EventService {

        private final EventRepository repository;
        private final ReentrantLock fairLock;

        @Autowired
        public EventServiceImpl(@Qualifier("eventRepository") final EventRepository repository) {
            this.repository = requireNonNull(repository, "repository can't be null");
            this.fairLock = new ReentrantLock(true);
        }

        @Override
        public void syncOperation() {
            log.debug("thread try to acquire lock");
            boolean isLockAcquired = false;
            try {
               isLockAcquired = fairLock.tryLock(10, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
               throw new IllegalStateException(e);
            }

            if (isLockAcquired) {
               try {
                  log.debug("{} own the lock", Thread.currentThread().getName());
                  // heavy operation
                  Thread.sleep(2000);
               } catch (InterruptedException e) {
                  throw new IllegalStateException(e);
               } finally {
                  fairLock.unlock();
                  log.debug("thread unlock");
               }
           }

           log.debug("thread - {} end of method", Thread.currentThread().getName());
       }
    ...
}

Bash код, который вызывает конечную точку:

#!/bin/bash

MAX=$1

for (( c=1; c<=MAX; c++ ))
do
   curl -X PUT http://localhost:2000/app/event/sync > /dev/null 2>&1 &
done

Вызов:

./sync.sh 5

Это запустит 5 процессов в фоновом режиме и 5 параллельных процессов вызовут конечную точку.

Журнал сообщений :

15:59:22.026 [task-1] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread try to aquire lock
15:59:22.026 [task-2] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread try to aquire lock
15:59:22.026 [task-3] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread try to aquire lock
15:59:22.026 [task-5] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread try to aquire lock
15:59:22.026 [task-4] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread try to aquire lock
15:59:22.026 [task-2] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - task-2 own the lock
15:59:24.027 [task-2] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread unlock
15:59:24.027 [task-3] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - task-3 own the lock
15:59:24.027 [task-2] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread - task-2 end of method
15:59:26.027 [task-3] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread unlock
15:59:26.028 [task-3] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread - task-3 end of method
15:59:26.028 [task-1] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - task-1 own the lock
15:59:28.029 [task-1] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread unlock
15:59:28.029 [task-5] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - task-5 own the lock
15:59:28.029 [task-1] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread - task-1 end of method

В примере мы видим, что поток task-2 успешно получает блокировку, а другие потоки пытаются получить блокировку, и они блокируются до task-2 снять блокировку, и thread-4 не получило блокировку в соответствующее время.

Я думаю, что эта часть интересна:

15:59:22.026 [task-2] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - task-2 own the lock
15:59:24.027 [task-2] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread unlock
15:59:24.027 [task-3] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - task-3 own the lock
15:59:24.027 [task-2] DEBUG hu.gaszabo.persistence.app.application.EventServiceImpl - thread - task-2 end of method

task-2 поток получил блокировку, через 2 секунды он снял блокировку, задача-3 поток немедленно получил блокировку до задача-2 сообщение об окончании потока завершено.

ответ от вас Вопрос может заключаться в том, что некоторые операции происходят одновременно (было бы лучше увидеть метки времени), но в журнале показано, что вы можете неправильно понять (например, то, что я показал, представляет эту ситуацию).

...