Сомнение в потоке Java

#java

#java

Вопрос:

Рассмотрим эту программу:

 public class test {
    public static void main(String [] args){
        Runnable r = new Runnable() {
            public void run() {
                System.out.print("foo");
            }
        };
        Thread t = new Thread(r) {
            public void run() {
                System.out.print("bar");
            }
        };
        t.start();
    }
}
  

При запуске вывод

 bar
  

Я хотел бы знать, почему это так.

Мое понимание:

Мы создаем экземпляр анонимного внутреннего класса, который реализует Runnable, переопределяя метод run. И назначьте его r.

Затем мы передаем этот runnable конструктору класса Thread. Но мы также создаем новый анонимный внутренний класс, который расширяет поток, переопределяя run.

Итак, теперь у нас есть два метода запуска, и 2-й будет иметь предпочтение перед 1-м.

Я в замешательстве, пожалуйста, поправьте меня, если я ошибаюсь.

Также используются ли такие сумасшедшие вещи в реальном программировании на Java? (Мой профессор говорит «да», и это то, что заставляет нас двигаться дальше : D).

Ответ №1:

Хотя вы передаете исполняемый экземпляр конструктору, вы переопределяете метод run таким образом, что он не используется r .

Ответ №2:

Происходит то, что стандартный Thread.run метод вызывает run тот Runnable , который вы передали. В вашем случае вы переопределяете поведение потока и заменяете его run методом, который игнорирует заданное Runnable .

К сожалению, такие сумасшедшие вещи действительно происходят в реальном мире. Вот почему рекомендуется использовать инструменты статического анализа и модульные тесты, чтобы убедиться, что вы получаете ожидаемое поведение 🙂

Ответ №3:

Вы переопределяете поведение потока по умолчанию, когда переопределяете его метод run(). Таким образом, вы контролируете порядок и выполняется ли r вообще.

 public void run() { // ignores "r"
    System.out.print("bar");
}
  

или

 public void run() { 
    super.run(); // runs "r" first.
    System.out.print("bar");
}
  

или

 public void run() { 
    System.out.print("bar");
    super.run(); // runs "r" second.
}
  

или

 public void run() { 
    super.run(); // runs "r" first.
    System.out.print("bar");
    super.run(); // and runs "r" second.
}
  

или

 public void run() { 
    r.run(); // runs "r" first.
    System.out.print("bar");
    r.run(); // and runs "r" second.
}
  

Ответ №4:

Метод Thread.run() обычно проверяет, был ли поток создан с помощью runnable. В этом случае он вызывает Runnable.run() , в противном случае ничего не делает. Вы изменили это поведение, переопределив Thread.run() и, таким образом, ваш runnable никогда не вызывается.