在子类实例中看不到修改受保护的字段值
Modifying a protected field value is not seen in subclass instance
这是我 运行 遇到的一个奇怪情况。我有一个定义受保护字段的抽象基 class。还有一个修改字段的public方法。然后我有一些使用该字段的基础 class 的子classes。
我注意到当我调用 super-class 方法来修改字段时,对字段值的更改似乎 "carry through" 到 subclass.
另一件需要提及的事情是抽象class(因此它的子classes)实现了Runnable
。我认为这不会对我所看到的产生影响,但多线程不是我的强项。
抽象基础class:
public abstract class AbstractWidget implements Runnable {
// Other fields and methods omitted for brevity.
protected boolean running;
public void shutDown() {
running = false;
}
}
亚class:
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()
方法时,线程中的子 class 实例 运行ning 不会从它的循环和 return 中中断。
我以前多次使用修改 "the outside" 的布尔字段的技术来停止 "forever" 线程。我不明白这里发生了什么。
更新:
下面是被调用的代码示例。
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()
的调用从未 returns.
更新:
根据要求,我已经包含了我希望的完整(足够)的代码示例,因为我目前拥有它。注意:我采纳了建议并将受保护的 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;
}
}
}
在"main"逻辑中:
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);
}
你 运行 widget.shutDown();
紧接着 thread.start();
吗?
也许 widget.shutDown();
在 running = true;
代码之前有 运行 run()
方法
[捂脸]
事实证明,问题是线程处理挂起,无法检查 running
字段的状态。一旦我纠正了这个问题,它就工作得很好。
我确实更改了我的逻辑以使用 AtomicBoolean
而不是 boolean
,因此感谢您提供的有用建议。
这是我 运行 遇到的一个奇怪情况。我有一个定义受保护字段的抽象基 class。还有一个修改字段的public方法。然后我有一些使用该字段的基础 class 的子classes。
我注意到当我调用 super-class 方法来修改字段时,对字段值的更改似乎 "carry through" 到 subclass.
另一件需要提及的事情是抽象class(因此它的子classes)实现了Runnable
。我认为这不会对我所看到的产生影响,但多线程不是我的强项。
抽象基础class:
public abstract class AbstractWidget implements Runnable {
// Other fields and methods omitted for brevity.
protected boolean running;
public void shutDown() {
running = false;
}
}
亚class:
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()
方法时,线程中的子 class 实例 运行ning 不会从它的循环和 return 中中断。
我以前多次使用修改 "the outside" 的布尔字段的技术来停止 "forever" 线程。我不明白这里发生了什么。
更新:
下面是被调用的代码示例。
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()
的调用从未 returns.
更新:
根据要求,我已经包含了我希望的完整(足够)的代码示例,因为我目前拥有它。注意:我采纳了建议并将受保护的 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;
}
}
}
在"main"逻辑中:
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);
}
你 运行 widget.shutDown();
紧接着 thread.start();
吗?
也许 widget.shutDown();
在 running = true;
代码之前有 运行 run()
方法
[捂脸]
事实证明,问题是线程处理挂起,无法检查 running
字段的状态。一旦我纠正了这个问题,它就工作得很好。
我确实更改了我的逻辑以使用 AtomicBoolean
而不是 boolean
,因此感谢您提供的有用建议。