2013-11-26 2 views
14

У меня есть класс с именем MyThread, который расширяет класс Thread и реализовать run() function.When Я хочу, чтобы запустить его, я получил два пути:В чем разница между разными способами запуска потока?

  1. новый экземпляр и вызвать функцию, как: new MyThread().start()
  2. новый экземпляр и передайте экземпляр функции построения Thread в качестве параметра, а затем вызовите функцию начала Thread. Пример: (new Thread(new MyThread)).start();

Кто-нибудь может просто сказать разницу?

+4

Java '' Thread' implements' 'Runnable', поэтому вы можете передать его в качестве ссылки на' Thread' , который принимает параметр «Runnable» в качестве параметра. В принципе, «Thread», когда выполняется, просто выполнит метод 'run'' Runnable', это пропуск. Если ни один не передан, он просто выполнит собственный метод 'run' ... – MadProgrammer

+1

Возможный дубликат [" реализует Runnable "vs." extends Thread "] (http://stackoverflow.com/questions/541487/implements-runnable -vs-extends-thread) –

ответ

4

Ну, у вас есть два способа реализовать многопоточность.

  1. расширить Thread и использовать new MyThreand().start(), чтобы начать нить.

  2. реализация Runnable интерфейс. В этом состоянии вы можете использовать (new Thread(new MyThread)).start(); для запуска потока.

Для получения более подробной информации, то просто обратитесь к oracle official doc.

+3

Возможно, вы не должны вызывать Runnable «MyThread» во втором варианте, это очень запутанно. – TwoThe

19

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

Обычно вы либо продлить Thread, а затем вызвать его собственный start (ваш # 1), или вы бы реализовать Runnable, а затем использовать Thread, чтобы запустить его (ваш 2 #). Но вы не должны распространять Thread, а затем использовать другой Thread для его запуска.

С точки зрения того, что по-другому, если вам нужно сделать что-нибудь, чтобы контролировать или опрашивать нить, в первом случае вы бы использовать Thread методы на экземпляре вашего класса; во втором случае вы будете использовать их в экземпляре, создаваемом с помощью new Thread. Если вы продляете Thread, но запустите его через # 2, методы Thread на вашем экземпляре не имеют значения и могут ввести в заблуждение.

Это последний бит, вероятно, яснее с примерами:

Пример расширения Thread:

class Foo extends Thread { 
    public void run() { 
     // ... 
    } 
} 

// Create it 
Foo foo = new Foo(); 

// Start it 
foo.start(); 

// Wait for it to finish (for example) 
foo.join(); 

Примечание мы начали и присоединился нить через foo ссылки.

Пример реализации Runnable:

class Foo implements Runnable { 
    public void run() { 
     // ... 
    } 
} 

// Create it 
Foo foo = new Foo(); 

// Create a Thread to run it 
Thread thread = new Thread(foo); 

// Start it 
thread.start(); 

// Wait for it to finish (for example) 
thread.join(); 

Примечание мы начали и присоединился нить через thread ссылки.

Не это сделать:

class Foo extends Thread { 
    public void run() { 
     // ... 
    } 
} 

// Create it 
Foo foo = new Foo(); 

// Create a Thread to run it -- DON'T do this 
Thread thread = new Thread(foo); 

// Start it 
thread.start(); 

... потому что теперь у вас есть Thread#join доступны и foo и thread; который является правильным использовать? (Ответ: Один на thread, но это сбивает с толку, так что лучше не делать этого.)

+0

Каковы ваши предпосылки для предпочтения реализации «Runnable», а не «Thread»? – l0b0

+0

@ l0b0: Я действительно должен был сформулировать это по-другому (или, по отражению, просто оставил его), потому что это действительно зависит от того, что делает класс, предпочитаю ли я его реализацию или расширение. –

+0

«Ответственность» несет ответственность. Добавление к нему другого - нарушение принципа единой ответственности. –

1

MyThread экземпляр вы передаете только действуя как Runnable, а не как отдельную тему.

Там нет в принципе никакой разницы логически в обоих направлениях:

Что Thread внутренне делает на start() это, вызывает run() метод Runnable.

И когда вы делаете new Thread(new MyThread()).start(), вы просто избыточны, так как Thread сам реализует Runnable.

Но это не имеет никакого отношения к логике, поскольку метод run()MyThread будет вызываться новой нитью.

0

(новый Thread (новый MyThread)) старт().

каждая резьба реализует Runnable; в этом случае экземпляр MyThread используется как Runnable, новый поток вызывает метод выполнения, реализованный MyThread. Вы не сможете остановить поток (или управлять им любыми способами) с помощью MyThread.

1

Вы не должны этого делать. Создание потока изменяет некоторые переменные, такие как «число неразвернутых потоков» в ThreadGroup.

Хотя это не должно вызывать проблем, это плохой стиль и смущает людей («Почему он это сделал?» должен быть веской причиной! »).

0

Там нет абсолютно никакой разницы между тем, как вы начнете Нить (class implementing Runnable or extending Thread class)

Это только абстракция, вы применяете, обратите внимание (Runnable object, is more general, because the Runnable object can subclass a class other than Thread)Good Coding практики.

In both of the cases Thread.start() will called 
1

Если сам ваш класс расширяет Thread вы можете следить за первый путь:

MyThread myThread = new MyThread(); 
myThread.start(); 

Если посмотреть в JavaDoc, вы увидите, что ваш второй путь направлен в сторону классов, которые (только) реализовать Runnable (что означает, что вашему классу просто необходимо реализовать метод run()).

public class MyClass implements Runnable { 
    public void run() { ... } 
} 

Thread thread = new Thread(new MyClass()); 
thread.start(); 

Разница заключается в том, что Runnable только интерфейс, тогда как Thread является классом.Это означает, что если вы хотите, чтобы ваша логика была частью класса, который по какой-то причине нуждается в расширении другого класса, вы все равно можете реализовать Runnable и использовать второй способ.

1

Резьба сама является реализацией Runnable. Когда создайте экземпляр Thread и запустите его, он выполнит собственный метод run(). Если ненулевойRunnable target дан это конструктор, то он будет ссылаться на это run() метод цели, как это видно из реализованных run() метода Thread класса:

@Override 
    public void run() { 
     if (target != null) { 
      target.run(); 
     } 
    } 

Два способа создания нового потока выполнения :

  1. Сначала один, чтобы объявить класс (т.е. PThread), чтобы быть подклассом Thread: PThread extends PThread и должен переопределить run метод class Тема. Теперь мы можем легко создать Instantiate этого класса и вызвать start() на нем:

    PThread pThread = new PThread(args); 
    pThread.start(); 
    
  2. Второй один является объявить класс, который реализует интерфейс Runnable: RThread implements Runnable затем реализует метод run. Мы должны создать экземпляр RThread и передать его в Thread например, в качестве Runnable цели:

    RunThread rThread = new RunThread(args); // args constructor argument if required 
    Thread t = new Thread(rThread); 
    t.start(); 
    

Как вы видели из приведенного выше способа начать нить, это фактически позволило класс, расширяющий Thread, например PThread, который должен быть передан новому конструктору Thread в качестве цели Runnable, чтобы запустить его. Потому что Thread сам по себе является реализацией Runnable.

PThread pThread = new PThread(args); 
    Thread t = new Thread(pThread); 
     // allowed as pThread is extending Thread and hence, 
     //an implementation of Runnable 
    t.start(); 

Но эта операция не нужна или, скорее, вы не должны этого делать. Поскольку pThread уже является Thread, мы могли бы просто позвонить pThread.start(), чтобы выполнить его метод run(), который является сердцем Thread. Создание другого потока только для выполнения pThread - это просто дополнительные накладные расходы, поскольку он не будет выполнять ничего, кроме выполнения метода pThreadrun().

Однако на самом деле вы не должны использовать расширение Thread. Так,

реализующего Runnable всегда предпочтительнее расширяя тему:

  • Наследования всех метод темы являются дополнительными накладными расходами только для представления задачи, которые можно легко сделать с Runnable.

  • Внедрение Runnable в класс по-прежнему позволяет нам продлить его до другого класса, если это необходимо.

  • В ООП расширение класса обычно означает добавление новых функций, изменение или улучшение поведения. Если мы не вносим никаких изменений в Thread или не изменяем его поведение, чем вместо этого используйте Runnable interface.

  • Runnable интерфейс представляет собой задачу, которая может быть выполнена либо простой Thread, либо Executors или любым другим способом. поэтому логическое разделение Задачи как Runnable, чем Thread - хорошее дизайнерское решение.

  • Executors, что облегчает жизнь при многопоточности, принимает Runnable как задачу.

Ссылка:

  1. Class Thread
  2. Difference between Thread class and Runnable interface
Смежные вопросы