Java 多线程中的侦听器仅在匿名传递时调用,而不是在声明为成员时调用

Java 多线程中的侦听器仅在匿名传递时调用,而不是在声明为成员时调用,java,multithreading,listener,Java,Multithreading,Listener,编辑 我想出来了: 我初始化服务成员的顺序很重要!其他成员(在我的示例中未显示)通过调用服务gettergetTimer()(也未显示)来引用Runnables中的计时器。在此getter中,侦听器已注册,但尚未初始化,因为它是在其他成员之后而不是之前声明/初始化的。叹息 我有一个类服务和一个内部类计时器,它在一个单独的线程中运行。此计时器接受一个滴答监听器,当计时器运行时,会以固定的时间间隔调用该监听器 其要点如下: public class Service { private Tim

编辑

我想出来了:

我初始化
服务
成员的顺序很重要!其他成员(在我的示例中未显示)通过调用
服务
getter
getTimer()
(也未显示)来引用
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
等),通过调用
服务
getter
getTimer()
使用
计时器
。在这个getter中,我注册了侦听器,但是侦听器是在其他成员之后而不是之前初始化的。一旦我改变了顺序,一切正常。我想我需要重新思考我的策略,因为这样有点脆弱。无论如何,再次感谢你的回答和评论中的宝贵见解!谢谢你调查这件事。我已经尽可能地从更复杂的代码中提取问题。我正在Android Studio中从事一个Android项目,到目前为止,我还不需要像这样隔离代码。我现在太累了,想不出如何在Android Studio中运行这样一个孤立的示例,但我明天会这么做。但如果这一切都很好,正如你所展示的,那么问题显然就出在其他地方。我必须找出导致这个问题的其他原因,因为这个问题确实是由匿名到成员侦听器引起的。再次感谢。很高兴这有帮助。我用IntelliJ Idea运行了它。是的,你是对的,这可能不是一个侦听器成为成员变量的问题。尝试查看导致未触发操作的其他原因。试着设置一个断点,在一个接近的时刻查看该侦听器是否被gc’ed了好吧,我想我找到了答案:这是我声明/初始化侦听器的顺序。其他
服务
成员(
Runnable
等),通过调用
服务
getter计时器