java - 在子类实例中看不到修改 protected 字段的值

标签 java abstract protected

这是我遇到的一个奇怪的情况。我有一个定义 protected 字段的抽象基类。还有一个修改字段的公共(public)方法。然后我有一些使用该字段的基类的子类。

我注意到,当我调用父类(super class)方法来修改字段时,对该字段值的更改似乎不会“传递”到子类的实例。

需要提到的另一件事是抽象类(及其子类)实现了Runnable。我不认为这会对我所看到的产生影响,但多线程不是我的强项。

抽象基类:

public abstract class AbstractWidget implements Runnable {
  // Other fields and methods omitted for brevity.
  protected boolean running;

  public void shutDown() {
    running = false;
  }
}

子类:

public class ConcreteWidget extends AbstractWidget {
  // Other fields and methods omitted for brevity.

  @Override
  public void run() {
    running = true;
    while (running) {
      // ...
    }
    logger.info("Shutting down");
  }
}

因此,当我最终调用 shutDown() 方法时,在线程中运行的子类实例不会中断循环并返回。

我之前曾多次使用从“外部”修改 boolean 字段的技术来停止“永远”线程。我不明白这里发生了什么。

更新:

下面是被调用的代码的示例。

ConcreteWidget widet = new ConcreteWidget(...);
thread = new Thread(widget);
thread.start();
logger.info("Started");

...

logger.debug("shutting down");
widget.shutDown();

try {
  logger.debug("doing join on thread");
  thread.join();
  logger.debug("returned from join");
} catch (InterruptedException e) {
  logger.error("Exception", e);
}

join() 的调用永远不会返回。

更新:

根据要求,我已经包含了我希望是一个完整(足够)的代码示例,就像我目前拥有的那样。注意:我已采纳建议并将 protected boolean 更改为 AtomicBoolean

public abstract class AbstractWidget implements Runnable {
  protected final AtomicBoolean   running  = new AtomicBoolean(true);
  public void shutDown() {
    running.set(false);
  }
}


public class ConcreteWidget extends AbstractWidget {
  @Override
  public void run() {
    while (running.get()) {
      // ... do stuff (including calling process() below)
    }
  }
  private void process() {
    try {
      // ... do stuff
    } catch (IOException e) {
      logger.error("Exception", e);
      running.set(false);
      return;
    }
  }
}

在“主要”逻辑中:

  private void startService() {
    widget = new ConcreteWidget(...);
    thread = new Thread(widget);
    thread.start();
    logger.info("Started");
  }

  public void close() {
    logger.debug("shutting down service");
    widget.shutDown();

    try {
      logger.debug("doing join on service thread");
      thread.join();
      logger.debug("returned from join");
    } catch (InterruptedException e) {
      logger.error("Exception", e);
    }
  }

顺便说一句,它仍然不起作用。

最佳答案

你的问题其实很简单。当您调用 widget.shutDown(); 时,线程尚未真正启动,因此当线程实际启动时,它将 running 设置回 true,并且永远不会停止。不要使用 running 来终止循环,而是使用单独的 stopped 变量。

public abstract class AbstractWidget implements Runnable {
  // Other fields and methods omitted for brevity.
  private volatile boolean running = false;
  private valatile boolean stopped = false;

  public boolean isRunning() {
    return running;
  }

  public boolean hasStopped() {
    return stopped;
  }

  public void shutDown() {
    stopped = true;
  }
}

public class ConcreteWidget extends AbstractWidget {
  // Other fields and methods omitted for brevity.

  @Override
  public void run() {
    running = true;
    while (!stopped) {
      // ...
    }
    running = false;
    logger.info("Shutting down");
  }
}

使用此设置,您可能需要在停止之前等待一段时间,否则循环将永远不会运行。

ConcreteWidget widet = new ConcreteWidget(...);
thread = new Thread(widget);
thread.start();
logger.info("Started");
...

try {
  Thread.sleep(500); // <--
} catch (Exception e) {}
logger.debug("shutting down");
widget.shutDown();

try {
  logger.debug("doing join on thread");
  thread.join();
  logger.debug("returned from join");
} catch (InterruptedException e) {
  logger.error("Exception", e);
}

关于java - 在子类实例中看不到修改 protected 字段的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50843547/

相关文章:

java - 根据 java 中其他元素的内容跳过特定元素的 XSD 验证

scala - Scala 中是否可以等于抽象类型成员?

c++ - 奇怪的编译器错误和模板继承

C++:可以继承类及其 protected 成员类型吗?

java - logback.xml中是否有像SizeAndTimeBasedTriggeringPolicy和FixedWindowRollingPolicy这样的触发策略?

Java递归查找日志

java - 在同一个 Scala 类上定义的抽象类和最终类

c++ - 纯虚类c++

c++ - 无法在赋值运算符中访问基类的 protected 方法

java - 构造ArrayAdaptor时出现Resources.NotFoundException