Repository: apache/dubbo
File: dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java (Java)

Code before:
                .getBean(FrameworkExecutorRepository.class)
                .getConnectivityScheduledExecutor();
        Configuration configuration = ConfigurationUtils.getGlobalConfiguration(url.getOrDefaultModuleModel());
        this.reconnectTaskTryCount = configuration.getInt(RECONNECT_TASK_TRY_COUNT, DEFAULT_RECONNECT_TASK_TRY_COUNT);
        this.reconnectTaskPeriod = configuration.getInt(RECONNECT_TASK_PERIOD, DEFAULT_RECONNECT_TASK_PERIOD);
        setRouterChain(routerChain);
    }

    @Override
    public List<Invoker<T>> list(Invocation invocation) throws RpcException {
        if (destroyed) {
            throw new RpcException(
                    "Directory of type " + this.getClass().getSimpleName() + " already destroyed for service "
                            + getConsumerUrl().getServiceKey() + " from registry " + getUrl());
        }

        BitList<Invoker<T>> availableInvokers;
        SingleRouterChain<T> singleChain = null;
        try {
            if (routerChain != null) {
                routerChain.getLock().readLock().lock();
            }
            boolean lockAcquired = false;
            try {
                if (!invokerRefreshReadLock.tryLock(LockUtils.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)) {
                    throw new RpcException("Failed to acquire read lock on invokerRefreshLock within timeout");
                }
                lockAcquired = true;
                // use clone to avoid being modified at doList().
                if (invokersInitialized) {
                    availableInvokers = validInvokers.clone();
                } else {
                    availableInvokers = invokers.clone();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RpcException(
                        "Interrupted while acquiring read lock for invoker access, cause: " + e.getMessage(), e);
            } finally {
                if (lockAcquired) {
                    invokerRefreshReadLock.unlock();
                }
            }

            if (routerChain != null) {
                singleChain = routerChain.getSingleChain(getConsumerUrl(), availableInvokers, invocation);
                singleChain.getLock().readLock().lock();
            }
            List<Invoker<T>> routedResult = doList(singleChain, availableInvokers, invocation);
            if (routedResult.isEmpty()) {
                // 2-2 - No provider available.

Review comment (bug):
The error message "Failed to acquire read lock on invokerRefreshLock within timeout" should include more context to help with debugging. Consider adding information such as the current lock state, whether it's held by a write lock, the timeout value used, and the service being accessed. This will make troubleshooting lock contention issues much easier in production environments.

Code after:
                .getBean(FrameworkExecutorRepository.class)
                .getConnectivityScheduledExecutor();
        Configuration configuration = ConfigurationUtils.getGlobalConfiguration(url.getOrDefaultModuleModel());
        this.reconnectTaskTryCount = configuration.getInt(RECONNECT_TASK_TRY_COUNT, DEFAULT_RECONNECT_TASK_TRY_COUNT);
        this.reconnectTaskPeriod = configuration.getInt(RECONNECT_TASK_PERIOD, DEFAULT_RECONNECT_TASK_PERIOD);
        setRouterChain(routerChain);
    }

    @Override
    public List<Invoker<T>> list(Invocation invocation) throws RpcException {
        if (destroyed) {
            throw new RpcException(
                    "Directory of type " + this.getClass().getSimpleName() + " already destroyed for service "
                            + getConsumerUrl().getServiceKey() + " from registry " + getUrl());
        }

        BitList<Invoker<T>> availableInvokers;
        SingleRouterChain<T> singleChain = null;
        try {
            if (routerChain != null) {
                routerChain.getLock().readLock().lock();
            }
            boolean lockAcquired = false;
            try {
                if (!invokerRefreshReadLock.tryLock(LockUtils.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)) {
                    throw new RpcException(
                            "Failed to acquire read lock on invokerRefreshLock within timeout. " + "Timeout: "
                                    + LockUtils.DEFAULT_TIMEOUT + "ms, " + "Lock state: [readLockHeld="
                                    + invokerRefreshLock.getReadLockCount() + ", writeLockHeld="
                                    + invokerRefreshLock.isWriteLocked() + ", writeLockHeldByCurrentThread="
                                    + invokerRefreshLock.isWriteLockedByCurrentThread() + "], Service: "
                                    + getConsumerUrl().getServiceKey());
                }
                lockAcquired = true;
                // use clone to avoid being modified at doList().
                if (invokersInitialized) {
                    availableInvokers = validInvokers.clone();
                } else {
                    availableInvokers = invokers.clone();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RpcException(
                        "Interrupted while acquiring read lock for invoker access, cause: " + e.getMessage(), e);
            } finally {
                if (lockAcquired) {
                    invokerRefreshReadLock.unlock();
                }
            }

            if (routerChain != null) {