Repository: open-telemetry/opentelemetry-java
File: sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/export/PeriodicMetricReader.java (Java)

Code before:
      scheduler.shutdownNow();
      // reset the interrupted status
      Thread.currentThread().interrupt();
    } finally {
      CompletableResultCode shutdownResult = scheduled.shutdown();
      shutdownResult.whenComplete(
          () -> {
            if (!shutdownResult.isSuccess()) {
              result.fail();
            } else {
              result.succeed();
            }
          });
    }
    return result;
  }

  @Override
  public void register(CollectionRegistration collectionRegistration) {
    this.collectionRegistration = collectionRegistration;
    start();
  }

  /**
   * Sets the {@link MeterProvider} to export metrics about this {@link PeriodicMetricReader} to.
   * Automatically called by the meter provider the reader is registered to.
   */
  void setMeterProvider(MeterProvider meterProvider) {
    this.scheduled.setMeterProvider(meterProvider);
  }

  @Override
  public String toString() {
    return "PeriodicMetricReader{"
        + "exporter="
        + exporter
        + ", intervalNanos="
        + intervalNanos
        + '}';
  }

  void start() {
    synchronized (lock) {
      if (scheduledFuture != null) {
        return;
      }
      scheduledFuture =
          scheduler.scheduleAtFixedRate(
              scheduled, intervalNanos, intervalNanos, TimeUnit.NANOSECONDS);
    }
  }

Review comment (performance):
Makes me think that SdkTracerProvider, SdkLoggerProvider should cascade set meter provider on all child components (i.e. BatchSpanProcessor, exporters, etc). Problem is, the `setMeterProvider` methods on child components are on the builders... Probably could have had something more elegant with some foresight. Too bad.

Code after:
      scheduler.shutdownNow();
      // reset the interrupted status
      Thread.currentThread().interrupt();
    } finally {
      CompletableResultCode shutdownResult = scheduled.shutdown();
      shutdownResult.whenComplete(
          () -> {
            if (!shutdownResult.isSuccess()) {
              result.fail();
            } else {
              result.succeed();
            }
          });
    }
    return result;
  }

  @Override
  public void register(CollectionRegistration collectionRegistration) {
    this.collectionRegistration = collectionRegistration;
    start();
  }

  /**
   * Sets the {@link MeterProvider} to export metrics about this {@link PeriodicMetricReader} to.
   * Automatically called by the meter provider the reader is registered to.
   */
  @SuppressWarnings("UnusedMethod")
  private void setMeterProvider(MeterProvider meterProvider) {
    this.scheduled.setMeterProvider(meterProvider);
  }

  @Override
  public String toString() {
    return "PeriodicMetricReader{"
        + "exporter="
        + exporter
        + ", intervalNanos="
        + intervalNanos
        + '}';
  }

  void start() {
    synchronized (lock) {
      if (scheduledFuture != null) {
        return;
      }
      scheduledFuture =
          scheduler.scheduleAtFixedRate(
              scheduled, intervalNanos, intervalNanos, TimeUnit.NANOSECONDS);
    }