Source:
<code>public void start() { synchronized (stateChangeLock) { Preconditions.checkState(!started, "already started"); Preconditions.checkState(!exec.isShutdown(), "already stopped"); try { consumer = getKafkaConsumer(); exec.submit( () -> { try { <START> while (!Thread.currentThread().isInterrupted() && !stopped) { <END> final Notice notice = notices.take(); try { notice.handle(); } catch (Throwable e) { log.makeAlert(e, "KafkaSupervisor[%s] failed to handle notice", dataSource) .addData("noticeClass", notice.getClass().getSimpleName()) .emit(); } } } catch (InterruptedException e) { log.info("KafkaSupervisor[%s] interrupted, exiting", dataSource); } } ); firstRunTime = DateTimes.nowUtc().plus(ioConfig.getStartDelay()); scheduledExec.scheduleAtFixedRate( buildRunTask(), ioConfig.getStartDelay().getMillis(), Math.max(ioConfig.getPeriod().getMillis(), MAX_RUN_FREQUENCY_MILLIS), TimeUnit.MILLISECONDS ); reportingExec.scheduleAtFixedRate( updateCurrentAndLatestOffsets(), ioConfig.getStartDelay().getMillis() + INITIAL_GET_OFFSET_DELAY_MILLIS, Math.max( tuningConfig.getOffsetFetchPeriod().getMillis(), MINIMUM_GET_OFFSET_PERIOD_MILLIS ), TimeUnit.MILLISECONDS ); reportingExec.scheduleAtFixedRate( emitLag(), ioConfig.getStartDelay().getMillis() + INITIAL_EMIT_LAG_METRIC_DELAY_MILLIS, monitorSchedulerConfig.getEmitterPeriod().getMillis(), TimeUnit.MILLISECONDS ); started = true; log.info( "Started KafkaSupervisor[%s], first run in [%s], with spec: [%s]", dataSource, ioConfig.getStartDelay(), spec.toString() ); } catch (Exception e) { if (consumer != null) { consumer.close(); } log.makeAlert(e, "Exception starting KafkaSupervisor[%s]", dataSource) .emit(); throw Throwables.propagate(e); } } }</code><technical_language>In addition this, I suggest adding a timeout take(). this thread block take() get check !stopped. If take() times out, check stopped, if false, run take() (again, a timeout)</technical_language>

Target:
public void start() { synchronized (stateChangeLock) { Preconditions.checkState(!started, "already started"); Preconditions.checkState(!exec.isShutdown(), "already stopped"); try { consumer = getKafkaConsumer(); exec.submit( () -> { try { long pollTimeout = Math.max(ioConfig.getPeriod().getMillis(), MAX_RUN_FREQUENCY_MILLIS); while (!Thread.currentThread().isInterrupted() && !stopped) { final Notice notice = notices.poll(pollTimeout, TimeUnit.MILLISECONDS); if (notice == null) { continue; } try { notice.handle(); } catch (Throwable e) { log.makeAlert(e, "KafkaSupervisor[%s] failed to handle notice", dataSource) .addData("noticeClass", notice.getClass().getSimpleName()) .emit(); } } } catch (InterruptedException e) { log.info("KafkaSupervisor[%s] interrupted, exiting", dataSource); } } ); firstRunTime = DateTimes.nowUtc().plus(ioConfig.getStartDelay()); scheduledExec.scheduleAtFixedRate( buildRunTask(), ioConfig.getStartDelay().getMillis(), Math.max(ioConfig.getPeriod().getMillis(), MAX_RUN_FREQUENCY_MILLIS), TimeUnit.MILLISECONDS ); reportingExec.scheduleAtFixedRate( updateCurrentAndLatestOffsets(), ioConfig.getStartDelay().getMillis() + INITIAL_GET_OFFSET_DELAY_MILLIS, Math.max( tuningConfig.getOffsetFetchPeriod().getMillis(), MINIMUM_GET_OFFSET_PERIOD_MILLIS ), TimeUnit.MILLISECONDS ); reportingExec.scheduleAtFixedRate( emitLag(), ioConfig.getStartDelay().getMillis() + INITIAL_EMIT_LAG_METRIC_DELAY_MILLIS, monitorSchedulerConfig.getEmitterPeriod().getMillis(), TimeUnit.MILLISECONDS ); started = true; log.info( "Started KafkaSupervisor[%s], first run in [%s], with spec: [%s]", dataSource, ioConfig.getStartDelay(), spec.toString() ); } catch (Exception e) { if (consumer != null) { consumer.close(); } log.makeAlert(e, "Exception starting KafkaSupervisor[%s]", dataSource) .emit(); throw Throwables.propagate(e); } } }