Чому Thread не є абстрактним класом, а start () не остаточним?


79

Чому Threadклас був реалізований як звичайний клас, а не абстрактний клас з run()методом, що є абстрактним.

Чи може це створити якісь проблеми? Або це має якусь користь бути таким?

Крім того, Thread.start()метод повинен бути дуже специфічним методом , функціональність якого не може бути реалізована жодним іншим класом (якщо я не помиляюся). І отже, я думаю, finalключове слово було б придатним для цього більше, ніж будь-який інший метод.

Але я можу замінити цей метод і використовувати його як завгодно,

public class Test extends Thread {
    public static void main (String... args) {
        Thread test = new Test();
        test.start();
    }

    @Override
    public void run() {
        System.out.println("New thread started...");
    }

    @Override
    public void start() {
        System.out.println("Did anyone tell you I will spawn a new thread??");
    }
}

Воно, очевидно, лише друкувалось,

Хтось тобі казав, що я породжу нову нитку ??

Чи є користь у перевизначенні крім заплутування інженера, який вас замінює?

Якщо ні, чому метод не був оголошений остаточним у класі Thread?


Тут ви викликаєте метод start як член класу ... його не викликають із планувальника ...
CoderNeji

2
Просто для ясності - ви запитуєте, чому Thread.run () не є абстрактним, оскільки користувачам потрібно його замінити, і чому Thread.start () не є остаточним, оскільки взагалі немає сенсу його замінювати? Гарне питання! Я помічаю, що хтось проголосував - цікаво, чому?
NickJ

3
Я б хотів, щоб Threadклас був остаточним. Конструктор вже бере запущений, тому для створення потоку не потрібно успадкування.
вправо

Відповіді:


50

Чому клас Thread був реалізований як звичайний клас, а не абстрактний клас із абстрактним методом run ().

Це питання насправді зводиться до того, що ви завжди повинні віддавати перевагу композиції перед спадщиною.

Якби Threadклас було оголошено як abstract, мова повинна була б надати інший клас, що поширюється на нього, який програмісти могли б використовувати для створення Thread. Ваше запитання буде потім про те, чому цей клас extendsвід ThreadНЕ abstract. Якби мова не передбачала іншого класу, extendsз якого Thread, програмістам довелося б створити власний клас, який extendпоходить із Threadі замінює run()метод.

Якщо ні, чому метод не був оголошений остаточним у класі Thread ??

Єдине можливе пояснення, яке я можу дати, - це те, що розробники мови бачили деякі варіанти використання для заміщення, startколи клас був представлений в JDK. Першою версією Java, якою я користувався, була 1.5, і я особисто не стикався з випадком використання, коли я знайшов необхідність перевизначити start. Як зазначив у відповіді Дж. Б. Нізет

якби сьогодні Java була перероблена з нуля, є велика ймовірність, що дизайн був би іншим


1
Хоча вам не потрібно розширювати клас Thread для іменування потоку (це було б просто викликати Thread.setName ()), частина, що пояснює, чому клас не може бути абстрактним, є дуже чіткою та точною ...
Codebender

@Codebender Погоджено. Я видалив це зі своєї відповіді, оскільки це не був хорошим прикладом, а також тому, що у вашому питанні не було запитання, коли продовжувати нитку.
CKing

Це чистий дизайн; чому б сьогодні було інакше?
Уоррен Дью

76

Звичайно, ви можете вистрілити собі в ногу, але це не означає, що потрібно.

Чому клас Thread був реалізований як звичайний клас, а не абстрактний клас із абстрактним методом run ().

Оскільки рекомендованим способом створення стартового потоку є не підклас Thread. Рекомендований спосіб - це визначити a Runnableта передати його як аргумент конструктору Thread:

Runnable r = new Runnable() {
    @Override
    public void run() {
        ...
    }
};
Thread t = new Thread(r);
t.start();

І, отже, я вважаю, що остаточне ключове слово підходить для цього більше, ніж будь-який інший метод.

Так і ні. Ви не можете замінити реалізацію start () власною реалізацією, але ви можете зробити додаткові дії в start (), якщо хочете:

@Override
public void start() {
    System.out.println("Did anyone tell you I will spawn a new thread??");
    super.start();
}

Тим не менш, якби сьогодні було перероблено Java з нуля, є велика ймовірність, що дизайн буде іншим. Пам’ятайте, що цей клас походить з Java 1.0 і досі сумісний із зворотною функцією.


Я цитував вас у своїй відповіді. Сподіваюся, це добре з вами :)
CKing

11
Нема проблем. Це з відкритим кодом.
JB Nizet

2
@NayukiMinase no. Інтерфейси завжди були на мові. Працює з JDK 1.0.
JB Nizet

На жаль, я заплутався з тим, як нову систему обробки подій AWT на основі зворотних викликів інтерфейсу (а не заміщення методу) було введено в 1.1.
Наюкі

1
Різьба має чистий дизайн; чому б сьогодні бути інакше?
Уоррен Дью

40

Чому Thread.start()ні final?

Ви впевнені , що ніколи не захотіли б його замінити?

Class MyThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r) {
            @Override
            public void start() {
                LOGGER.info("Starting thread " + this);
                super.start();
            }
        };
    }
}

0

Я вважаю, що для відповідей слід опублікувати кілька калібрувань.

"Ви впевнені, що ніколи не захотіли б це замінити?"

Ні ! Я б не. Це як сказати: "Ви впевнені, що хочете оголосити цю змінну приватною?" Тому що якби я міг оголосити будь-яку змінну, яку я використовую, як загальнодоступну, не побоюючись, що інші розробники можуть зіпсувати мою логіку проектування, кодування буде легким. Однією з найважливіших цілей OOPS-концепцій Scope, абстракції, поліморфізму, обробки помилок тощо є інформування інших розробників про дизайн та наміри, що лежать у основі вашого коду. використовувати super.start (). @Codebender написав метод запуску для потоку без використання super.start (), і компілятор ніколи не скаржився. Отже, він вільний зламати весь механізм потокової роботи, а компілятор, мабуть, просто дозволить йому пройти? Метод запуску потоку гарантує, що метод запуску викликається і виконується в потрібний час! Це має вирішальне значення для самої концепції Threading. Я був би з радістю виправлений, якщо б щось тут пропустив. 2.

Оскільки рекомендованим способом створення стартового потоку є не підклас Thread.

Добре, якщо проектувальнику дозволено codebender підкласити Thread і зіпсувати метод запуску, За цією логікою, це сам дизайн, який стріляє в стопу. За іншою заявою (з якою я повністю погоджуюсь), Runnable - рекомендований спосіб. Тоді чому ми взагалі дозволяємо класу Thread створювати екземпляри потоку взагалі без обмежень? Далі йде:

Ви не можете замінити реалізацію start () власною реалізацією,

Це насправді підтримує твердження codebender, що метод запуску повинен бути остаточним, коли ви це говорите .. ^

Той єдиний момент, який є дійсним, вже згадується як допоміжна примітка, але це - фактичною відповіддю на це питання

"Зворотна сумісність".

Насправді вдосконалення відбувалися навіть до JDK 5.0, коли вони включали багато основних доповнень та роз'яснень до моделі паралельності Java. Ми хочемо, щоб зворотна сумісність підтримувалася на всьому шляху, і тому клас Thread залишається точно таким, як був раніше, навіть незважаючи на те, що на сьогоднішній день рекомендованим способом є Runnable interface.

Знову ж таки, я був би більш ніж радий, щоб мене виправили, якщо я щось пропустив.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.