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

Code before:
     */
    @Deprecated
    public ScheduledFuture<?> getConnectivityCheckFuture() {
        return connectivityCheckFuture;
    }

    public BitList<Invoker<T>> getInvokers() {
        // return clone to avoid being modified.
        return invokers.clone();
    }

    public BitList<Invoker<T>> getValidInvokers() {
        // return clone to avoid being modified.
        return validInvokers.clone();
    }

    public List<Invoker<T>> getInvokersToReconnect() {
        return invokersToReconnect;
    }

    public Set<Invoker<T>> getDisabledInvokers() {
        return disabledInvokers;
    }

    protected void setInvokers(BitList<Invoker<T>> invokers) {
        LockUtils.safeLock(invokerRefreshLock, 60_000, () -> {
            this.invokers = invokers;
            refreshInvokerInternal();
            this.invokersInitialized = true;
        });

        MetricsEventBus.publish(
                RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
    }

    protected void destroyInvokers() {
        // set empty instead of clearing to support concurrent access.
        LockUtils.safeLock(invokerRefreshLock, 60_000, () -> {
            this.invokers = BitList.emptyList();
            this.validInvokers = BitList.emptyList();
            this.invokersInitialized = false;
        });
    }

    private boolean addValidInvoker(Invoker<T> invoker) {
        AtomicBoolean result = new AtomicBoolean(false);
        LockUtils.safeLock(invokerRefreshLock, 60_000, () -> {
            result.set(this.validInvokers.add(invoker));
        });
        MetricsEventBus.publish(
                RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));

Review comment (suggestion):
This lock is not required because refreshInvokerInternal already has a sync lock.
So far, `invokersInitialized` and `invokers` repeat refresh is not a problem.
My suggestion is to remove the lock on refreshInvokerInternal.



Code after:
    }

    /**
     * for ut only
     */
    @Deprecated
    public ScheduledFuture<?> getConnectivityCheckFuture() {
        return connectivityCheckFuture;
    }

    public BitList<Invoker<T>> getInvokers() {
        // return clone to avoid being modified.
        return invokers.clone();
    }

    public BitList<Invoker<T>> getValidInvokers() {
        // return clone to avoid being modified.
        return validInvokers.clone();
    }

    public List<Invoker<T>> getInvokersToReconnect() {
        return invokersToReconnect;
    }

    public Set<Invoker<T>> getDisabledInvokers() {
        return disabledInvokers;
    }

    protected void setInvokers(BitList<Invoker<T>> invokers) {
        LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> {
            this.invokers = invokers;
            refreshInvokerInternal();
            this.invokersInitialized = true;
        });

        MetricsEventBus.publish(
                RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
    }

    protected void destroyInvokers() {
        // set empty instead of clearing to support concurrent access.
        LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> {
            this.invokers = BitList.emptyList();
            this.validInvokers = BitList.emptyList();
            this.invokersInitialized = false;
        });
    }

    private boolean addValidInvoker(Invoker<T> invoker) {
        AtomicBoolean result = new AtomicBoolean(false);
        LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> {