子线程看不到主线程进行的更新

时间:2018-09-14 00:17:03

标签: multithreading scala apache-spark thread-safety

我正在通过扩展Sp​​arkListener类来实现SparkHealthListener。

@Component
class ClusterHealthListener extends SparkListener with Logging {
  val appRunning = new AtomicBoolean(false)
  val executorCount = new AtomicInteger(0)

  override def onApplicationStart(applicationStart: SparkListenerApplicationStart) = {
    logger.info("Application Start called .. ")
    this.appRunning.set(true)
    logger.info(s"[appRunning = ${appRunning.get}]")
  }

  override def onExecutorAdded(executorAdded: SparkListenerExecutorAdded) = {
    logger.info("Executor add called .. ")
    this.executorCount.incrementAndGet()
    logger.info(s"[executorCount = ${executorCount.get}]")
  }
}

appRunning executorCount 是在ClusterHealthListener类中声明的两个变量。 ClusterHealthReporterThread将仅读取值。

@Component
class ClusterHealthReporterThread @Autowired() (healthListener: ClusterHealthListener) extends Logging {
  new Thread {
    override def run(): Unit = {
      while (true) {
          Thread.sleep(10 * 1000)
          logger.info("Checking range health")
          logger.info(s"[appRunning = ${healthListener.appRunning.get}] [executorCount=${healthListener.executorCount.get}]"
      }
    }
  }.start()
}

ClusterHealthReporterThread总是报告初始化值,而不管主线程对该变量所做的更改如何?我究竟做错了什么?这是因为我将healthListener注入ClusterHealthReporterThread吗?

更新

我玩了一段时间,看起来与启动火花监听器的方式有关。

如果我这样添加火花监听器

val sparkContext = SparkContext.getOrCreate(sparkConf) sparkContext.addSparkListener(healthListener)

父线程始终将 appRunning 显示为“ false”,但显示执行程序计数正确。子线程(运行状况报告程序)也将显示正确的执行程序计数,但 appRunning 始终像主线程一样报告“ false”。

然后我偶然发现了这个Why is SparkListenerApplicationStart never fired?,并尝试在spark配置级别设置侦听器,

.set("spark.extraListeners", "HealthListener class path")

如果我这样做,主线程将为 appRunning 报告'true',并报告正确的执行者计数,但是子线程将始终报告'false'和'0'执行者的价值。

1 个答案:

答案 0 :(得分:1)

我无法立即看到这里出了什么问题,您可能已经找到了一个有趣的边缘案例。

我认为@ m4gic的注释可能是正确的,日志记录库可能正在缓存该插值字符串?看来您正在使用https://github.com/lightbend/scala-logging,它声称此插值“对行为没有影响”,所以也许没有。请您能按照他的建议重试而不使用该功能并返回报告吗?

第二种可能性:我想知道系统中是否只有一个ClusterHealthListener?也许自动装配导致创建了第二个实例?您可以在两个位置记录ClusterHealthListener引用中的object ids并验证它们是同一对象吗?

如果这些建议都不能解决此问题,您能否发布一个可以与我一起玩的工作示例?