Слушатель в многопоточности вызывается только когда передается анонимно, а не когда объявляется участником - PullRequest
0 голосов
/ 05 февраля 2020

Редактировать

Я понял:

Порядок, в котором я инициализировал Service членов, был важен! Другие члены (не показанные в моих примерах) ссылаются на Timer в Runnable s, вызывая Service getter getTimer() (также не показано). В этом получателе слушатель зарегистрирован, но еще не инициализирован, потому что он был объявлен / инициализирован после других членов, а не до их. Вздох ...


У меня есть класс Service и внутренний класс Timer, который выполняется в отдельном потоке. Этот таймер принимает прослушиватель тиков, который вызывается с фиксированными интервалами, когда таймер работает.

Суть этого такова:

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
      }
    });
  }
}

... слушатель вызывается просто отлично, когда запускается таймер.

Однако, когда я регистрирую слушателя тика как члена моего Service класс, вот так (я пробовал несколько различных перестановок public, final, volatile, et c. также):

class Service {

  private Timer timer;
  private Timer.TickListener timerTickListener = new Timer.TickListener() {
    @Override
    void onTick(Timer timer) {
      // this will NOT get called
    }
  };

  Service() {
    timer = new Timer();
    timer.setTickListener(timerTickListener);
  }
}

... the Слушатель не вызывается при запуске таймера.

Я подозреваю, что эта проблема связана с многопоточностью, потому что подобные настройки работают просто отлично, когда не охватывает разные потоки , но я не достаточно разбираюсь в многопоточности, чтобы точно понять, почему это не работает.

Можете ли вы пролить свет на эту проблему?

Это как-то связано с доступом объекты по ссылке в разных потоках, возможно? Или это что-то другое?

1 Ответ

2 голосов
/ 05 февраля 2020

Вы утверждали, что при регистрации 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();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...