@Override
    public FlowExecution getFlowExecution(final FlowExecutionKey key) throws FlowExecutionRepositoryException {
        if (key instanceof final ClientFlowExecutionKey clientFlowExecutionKey) {
            try {
                val encoded = clientFlowExecutionKey.getData();
                val state = (SerializedFlowExecutionState) determineTranscoder().decode(encoded);

                if (webflowProperties.getSession().isPinToSession()) {
                    verifyWebflowSessionIsCorrectlyPinned(state);
                }
                val conversationScope = state.getConversationScope();
                val flow = flowDefinitionLocator.getFlowDefinition(state.getFlowId());
                return flowExecutionFactory.restoreFlowExecution(state.getExecution(), flow, key, conversationScope, this.flowDefinitionLocator);
            } catch (final Exception e) {
                throw new ClientFlowExecutionRepositoryException("Error decoding flow execution", e);
            }
        }
        throw new IllegalArgumentException("Expected instance of ClientFlowExecutionKey but got " + key.getClass().getName());
    }
Client flow storage has not backing store independent from the flow key, so no locking is required.
core/cas-server-core-webflow-api/src/main/java/org/apereo/cas/web/flow/executor/ClientFlowExecutionRepository.java