Java 多线程中的侦听器仅在匿名传递时调用,而不是在声明为成员时调用
编辑 我想出来了: 我初始化Java 多线程中的侦听器仅在匿名传递时调用,而不是在声明为成员时调用,java,multithreading,listener,Java,Multithreading,Listener,编辑 我想出来了: 我初始化服务成员的顺序很重要!其他成员(在我的示例中未显示)通过调用服务gettergetTimer()(也未显示)来引用Runnables中的计时器。在此getter中,侦听器已注册,但尚未初始化,因为它是在其他成员之后而不是之前声明/初始化的。叹息 我有一个类服务和一个内部类计时器,它在一个单独的线程中运行。此计时器接受一个滴答监听器,当计时器运行时,会以固定的时间间隔调用该监听器 其要点如下: public class Service { private Tim
服务
成员的顺序很重要!其他成员(在我的示例中未显示)通过调用服务gettergetTimer()
(也未显示)来引用Runnable
s中的计时器。在此getter中,侦听器已注册,但尚未初始化,因为它是在其他成员之后而不是之前声明/初始化的。叹息
我有一个类服务
和一个内部类计时器
,它在一个单独的线程中运行。此计时器接受一个滴答监听器,当计时器运行时,会以固定的时间间隔调用该监听器
其要点如下:
public class Service {
private Timer timer;
Service() {
// more to follow in code snippets below where I demonstrate the issue I am facing
}
private static class Timer
implements Runnable {
private interface TickListener {
void onTick(Timer timer);
}
private TickListener tickListener;
public void setTickListener(TickListener tickListener) {
this.tickListener = tickListener;
}
public void start() {
new Thread(this).start();
}
@Override
public void run() {
while(keepThreadRunningCondition) {
if(tickListener != null) {
// to verify that Timer is actually running
// and tickListener is not null
// I actually log here
// and the log appears just fine in all cases
tickListener.onTick(this);
}
}
}
}
}
现在,当我匿名注册滴答监听器时,如下所示:
class Service {
private Timer timer;
Service() {
timer = new Timer();
timer.setTickListener(new Timer.TickListener() {
@Override
void onTick(Timer timer) {
// this gets called perfectly fine
}
});
}
}
…当计时器启动时,侦听器会被很好地调用
但是,当我将滴答监听器注册为我的服务
类的成员时,就像这样(我也尝试了公共
、最终
、易失性
等几种不同的排列):
…当计时器启动时,侦听器不会被调用
我怀疑这个问题与多线程有关,因为类似的设置在不跨越不同线程时可以正常工作,但我对多线程的了解还不够透彻,无法确切理解为什么这样做不起作用
你能解释一下这个问题吗
它是否与跨不同线程通过引用访问对象有关?还是有什么不同?您声称,在将TickListener注册为服务的成员变量后,将不会调用onTicket
这是不对的。我自己运行代码,它被调用了
这是我的密码
package com.company;
public class Service {
private Timer timer;
Timer.TickListener tickListener = new Timer.TickListener() {
@Override
public void onTick(Timer timer) {
// this gets called perfectly fine
System.out.println(42);
}
};
Service() {
// more to follow in code snippets below where I demonstrate the issue I am facing
timer = new Timer();
timer.setTickListener(tickListener);
}
private static class Timer
implements Runnable {
private interface TickListener {
void onTick(Timer timer);
}
private TickListener tickListener;
public void setTickListener(TickListener tickListener) {
this.tickListener = tickListener;
}
public void start() {
new Thread(this).start();
}
@Override
public void run() {
while(true) {
if(tickListener != null) {
// to verify that Timer is actually running
// and tickListener is not null
// I actually log here
// and the log appears just fine in all cases
tickListener.onTick(this);
}
try{
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void foo() {
timer.start();
}
public static void main(String[] args) {
Service service = new Service();
service.foo();
}
}
您声称在将TickListener注册为服务的成员变量时,将不会调用onTicket
这是不对的。我自己运行代码,它被调用了
这是我的密码
package com.company;
public class Service {
private Timer timer;
Timer.TickListener tickListener = new Timer.TickListener() {
@Override
public void onTick(Timer timer) {
// this gets called perfectly fine
System.out.println(42);
}
};
Service() {
// more to follow in code snippets below where I demonstrate the issue I am facing
timer = new Timer();
timer.setTickListener(tickListener);
}
private static class Timer
implements Runnable {
private interface TickListener {
void onTick(Timer timer);
}
private TickListener tickListener;
public void setTickListener(TickListener tickListener) {
this.tickListener = tickListener;
}
public void start() {
new Thread(this).start();
}
@Override
public void run() {
while(true) {
if(tickListener != null) {
// to verify that Timer is actually running
// and tickListener is not null
// I actually log here
// and the log appears just fine in all cases
tickListener.onTick(this);
}
try{
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void foo() {
timer.start();
}
public static void main(String[] args) {
Service service = new Service();
service.foo();
}
}
调用timer.start()
?@DakshinamurthyKarra在服务的另一种方法中的调用在哪里,但我向您保证,这不是问题所在。在这两种情况下,它的调用是相同的。注:我通过在Timer.run()内部登录来验证这一点。好的。那么,onTick
做什么呢?您是否在调用开始时进行日志记录以检查它是否被调用?@DakshinamurthyKarra是的,第一个示例从onTick
内部运行日志,很好,第二个示例从onTick
中不记录任何内容。注:事实上,我也在onTick
中写入数据库:第一个示例有效,第二个示例不向数据库写入任何内容。在服务的另一种方法中,timer.start()
?@DakshinamurthyKarra的调用在哪里?但我向您保证,这不是问题所在。在这两种情况下,它的调用是相同的。注:我通过在Timer.run()内部登录来验证这一点。好的。那么,onTick
做什么呢?您是否在调用开始时进行日志记录以检查它是否被调用?@DakshinamurthyKarra是的,第一个示例从onTick
内部运行日志,很好,第二个示例从onTick
中不记录任何内容。注:实际上,我也在onTick
中写入数据库:第一个示例有效,第二个示例不向数据库写入任何内容。感谢您对此进行研究。我已经尽可能地从更复杂的代码中提取问题。我正在Android Studio中从事一个Android项目,到目前为止,我还不需要像这样隔离代码。我现在太累了,想不出如何在Android Studio中运行这样一个孤立的示例,但我明天会这么做。但如果这一切都很好,正如你所展示的,那么问题显然就出在其他地方。我必须找出导致这个问题的其他原因,因为这个问题确实是由匿名到成员侦听器引起的。再次感谢。很高兴这有帮助。我用IntelliJ Idea运行了它。是的,你是对的,这可能不是一个侦听器成为成员变量的问题。尝试查看导致未触发操作的其他原因。试着设置一个断点,在一个接近的时刻查看该侦听器是否被gc’ed了好吧,我想我找到了答案:这是我声明/初始化侦听器的顺序。其他服务
成员(Runnable
等),通过调用服务
gettergetTimer()
使用计时器
。在这个getter中,我注册了侦听器,但是侦听器是在其他成员之后而不是之前初始化的。一旦我改变了顺序,一切正常。我想我需要重新思考我的策略,因为这样有点脆弱。无论如何,再次感谢你的回答和评论中的宝贵见解!谢谢你调查这件事。我已经尽可能地从更复杂的代码中提取问题。我正在Android Studio中从事一个Android项目,到目前为止,我还不需要像这样隔离代码。我现在太累了,想不出如何在Android Studio中运行这样一个孤立的示例,但我明天会这么做。但如果这一切都很好,正如你所展示的,那么问题显然就出在其他地方。我必须找出导致这个问题的其他原因,因为这个问题确实是由匿名到成员侦听器引起的。再次感谢。很高兴这有帮助。我用IntelliJ Idea运行了它。是的,你是对的,这可能不是一个侦听器成为成员变量的问题。尝试查看导致未触发操作的其他原因。试着设置一个断点,在一个接近的时刻查看该侦听器是否被gc’ed了好吧,我想我找到了答案:这是我声明/初始化侦听器的顺序。其他服务
成员(Runnable
等),通过调用服务
getter计时器