当前位置: 首页 > 知识库问答 >
问题:

在子类实例中看不到修改受保护的字段值

国仰岳
2023-03-14

这是我遇到的一个奇怪的情况。我有一个定义受保护字段的抽象基类。还有一个修改字段的公共方法。然后,我有基类的一些子类使用字段。

我注意到,当我调用超类方法来修改字段时,对字段值的更改似乎不会“贯彻”到子类的实例中。

需要提到的另一件事是抽象类(以及它的子类)实现了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()方法时,线程中运行的子类实例不会从它的循环中中断并返回。

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

更新:

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

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()的调用永远不会返回。

更新:

按照要求,我包含了我希望是完整的(足够的)代码示例,就像我目前所拥有的一样。注意:我采纳了这个建议,将受保护的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);
    }
  }

顺便说一句,它还是不行。

共有2个答案

柳宪
2023-03-14

是否在Thread.Start();之后立即运行Widget.Shutdown();

可能widget.shutdown();running=true之前运行;run()方法中的代码

黄弘新
2023-03-14

你的问题其实很简单。在调用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);
}
 类似资料:
  • 问题内容: 关键字授予对相同包和子类(http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html)中的类的访问权限。 现在,每个类都有一个超类(http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html)。 因此,我得出结论,即使每个类都可以访问的方法。

  • 问题内容: 我想从提供此受保护方法的类的子类中调用另一个实例的受保护方法。请参见以下示例: 告诉我。我看不到这的原因(我以为我已经在其他代码中这样做了)。我想保持此方法的保护,我该怎么办? 编辑 我想提供一个简化的版本,但我没有想到事实是,这些类位于不同的程序包中。 问题答案: 您可以通过子类化和重写来访问受保护的方法。当它们在同一包装中时也是如此。我将添加一些细节。您可以在此处阅读详细信息。 您

  • 在< code>/users下,我有一些需要身份验证令牌的路由,还有一些不需要。为了实现这一点,我做了以下工作。 然后我按照以下方式安装这些路线。 当我向< code>/users发送POST时,它运行预期的路径,但是当< code>next()被调用时,< code > protected _ middleware 运行。这是因为它在标有“D”的行中找到了下一个< code>/users定义。

  • 要使用注释,必须创建一个包含getters和setters的类: 但这会导致有人试图通过调用以下命令来修改此值: 有没有一种方法可以创建注释类,而不使用setter和外部解析器/读取器类?

  • 问题内容: 我在理解Java(或其背后的设计)中的受保护的访问修饰符时遇到了一些麻烦。我认为这意味着程序包访问和通过继承包含抽象成员的类的对象的访问。 我编写了以下示例代码。我看到,如果未注释,注释掉的行会产生编译错误。为什么我可以通过Second中的Second对象而不是Second中的First对象访问pro? 问题答案: 该网页链接@MadProgrammer给出了一个体面的解释: “ pr

  • 我正在阅读这本Java SCJP的书,我偶然发现了以下内容: 但是我得到了这个错误: 那么,出什么问题了?