Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Нити 
:(
    Опции темы
jGorets
Дата 22.9.2010, 00:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 30
Регистрация: 11.7.2010

Репутация: нет
Всего: нет



Кто как или где и в каких случаях лучше создавать потоки через интерфейс Runnable или используя класс Thread??
PM MAIL   Вверх
soulcub
Дата 22.9.2010, 06:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 2.2.2010
Где: Винница, Украина

Репутация: нет
Всего: 2



То-есть вопрос можно перефразировать как "Зачем нужны потоки?".

Не люблю отвечать ссылками, но вопрос то ведь элементарный..

http://www.quizful.net/post/java-threads

Тут неплохо написано про потоки.
--------------------
Так давай же, поспеши!Отыскать СВОЙ куб души!
PM MAIL ICQ   Вверх
nc30
Дата 22.9.2010, 10:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Интересующийся :)
*


Профиль
Группа: Участник
Сообщений: 140
Регистрация: 24.6.2010
Где: Санкт-Петербург

Репутация: 5
Всего: 8



Цитата(jGorets @ 21.9.2010,  22:47)
Кто как или где и в каких случаях лучше создавать потоки через интерфейс Runnable или используя класс Thread??

В двух словах: наследовать от Thread - более просто, реализовать Runnable - более гибко.

Создать потоковый класс наследованием от класса Thread весьма просто: наследовал класс, переопределил метод run(), создал объект, запустил на выполнение. Но наследовать наш потоковый класс от какого-либо другого мы уже не сможем, т. к. родитель в Java может быть только один и он уже есть - класс Thread.

Реализация интерфейса Runnable чуть более сложна в описании и требует несколько большего количества ресурсов. Все это происходит оттого, что класс, реализующий интерфейс Runnable - это еще не полноценный потоковый класс. Реализуя Runnable (определяя метод run()), мы объявляем, что объект теоретически способен к выполнению (able to be run), но настоящих потоковых методов (start(), wait() и еще с полсотни методов) у нашего класса нет. Для того, чтобы объект нашего класса действительно мог выполняться, ему нужен т. н. handler - управляющий поток. Handler - это полноценный поток, объект класса Thread. Образно говоря, он "взваливает" объект нашего класса (который - как мы уже выяснили - не совсем поток) к себе "на плечи" и полностью им управляет в отношении "потоковости", т. е. потоковые методы выполняются как раз handler'ом. К членам нашего класса, которые непосредственно не связаны с его "потоковостью", handler отношения не имеет.
Другими словами, наш класс, реализуя интерфейс Runnable, заявляет, что он готов исполнить "потоковый" контракт, а handler момогает ему этот контракт выполнить.
Все на самом деле очень просто smile (если не все сразу понятно, то приведенный ниже несложный код должен все пояснить).
Соответственно в этом случае (реализация Runnable), приходится чуть больше описывать. К тому же вместо одного объекта (как в случае наследования от Thread) создаются два - наш "поток" и управляющий поток. Зато этот вариант не связывает нам руки в отношении возможности наследования нашего класса, если это необходимо. 

А какой вариант выбрать - зависит от конкретной ситуации при разработке программы.
Код

package threads;

public class SimpleThread extends Thread {

    public SimpleThread() {
        // Установить имя потоку.
        setName("SimpleThread");
    }

    @Override
    public void run() {
        System.out.println("Hello from " + getName());
    }
}

Код

package threads;

public class ThreadRunnable implements Runnable {
    // Ссылка на управляющий поток.
    Thread handler;

    public ThreadRunnable() {
        // Создаем управляющий поток (this говорит о том, что управляемым
        //  будет "этот" поток - ThreadRunnable.
        handler = new Thread(this);
        // Устанавливаем имя управляющему потоку.
        handler.setName("ThreadRunnable");
    }

    @Override
    public void run() {
        System.out.println("Hello from " + handler.getName());
    }
}

Код

package threads;

public class Main {

    public static void main(String [] args) {
        SimpleThread st = new SimpleThread();
        // Старт потока.
        st.start();

        ThreadRunnable tr = new ThreadRunnable();
        // Старт потока через его handler.
        tr.handler.start();
    }
}


Это сообщение отредактировал(а) nc30 - 22.9.2010, 10:31
PM MAIL   Вверх
Skipy
Дата 22.9.2010, 12:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 6
Всего: 16



Добавлю пару слов. Иногда необходимо вызвать извне методы класса Thread, чаще всего это join и interrupt. В этом случае по любому где-то придется держать ссылку именно на Thread. В случае, когда ссылка нужна еще и на экземпляр нашей реализации потока - например, выставить какой-нибудь флаг, забрать какие-нибудь данные и т.п. - имеет смысл их совместить при возможности, и унаследоваться от Thread.


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
nc30
Дата 22.9.2010, 13:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Интересующийся :)
*


Профиль
Группа: Участник
Сообщений: 140
Регистрация: 24.6.2010
Где: Санкт-Петербург

Репутация: 5
Всего: 8



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

Цитата(Skipy @ 22.9.2010,  10:57)
 Иногда необходимо вызвать извне методы класса Thread, чаще всего это join и interrupt. В этом случае по любому где-то придется держать ссылку именно на Thread.

Это то, о чем вы говорите?
Код

public class ThreadRunnable implements Runnable {
    // Ссылка на управляющий поток.
    Thread handler;
    ...


Цитата(Skipy @ 22.9.2010,  10:57)
В случае, когда ссылка нужна еще и на экземпляр нашей реализации потока - например, выставить какой-нибудь флаг, забрать какие-нибудь данные и т.п. - имеет смысл их совместить при возможности, и унаследоваться от Thread.

Не очень понял, что именно имеет смысл совместить. Можно чуть подробнее?

Это сообщение отредактировал(а) nc30 - 22.9.2010, 13:46
PM MAIL   Вверх
Skipy
Дата 22.9.2010, 16:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 6
Всего: 16



Цитата
Это то, о чем вы говорите?


Не совсем. Внутри Вашего Runnable ссылку на поток получит ьне вопрос - Thread.currentThread(); Эта ссылка нужна вовне:

Код

Runnable myRunnable = new MyRunnable();
Thread t = new Thread(myRunnable, "My thread");
t.start();
t.join();


Ссылка t может понадобиться не сразу, а где-то в дальнейшем, когда надо прервать, например, этот поток, а он висит на мониторе. Флагом Вы этого не сделаете, а вот вызовом t.interrupt() ожидание на мониторе прерывается.

Цитата
Не очень понял, что именно имеет смысл совместить. Можно чуть подробнее?


Допустим, Вы создали реализацию Runnable, и Вам необходимо иметь возможность вызывать у нее какие-то методы. Т.е. Вам нужно сохранить ссылку на экземпляр этой реализации.  С другой стороны, Вам нужно иметь ссылку на поток, в котором этот экземпляр работает. Т.е. ссылок получается уже две, вп римере выше - это myRunnable и t. Вот чтобы не хранить две ссылки и не протаскивать их везде, где они нужны, можно унаследовать класс от Thread (а не от Runnable), и тогда ссылка нужна будет всего одна.


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
nc30
Дата 22.9.2010, 17:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Интересующийся :)
*


Профиль
Группа: Участник
Сообщений: 140
Регистрация: 24.6.2010
Где: Санкт-Петербург

Репутация: 5
Всего: 8



Цитата(Skipy @ 22.9.2010,  14:52)
Ссылка t может понадобиться не сразу, а где-то в дальнейшем, когда надо прервать, например, этот поток, а он висит на мониторе. Флагом Вы этого не сделаете, а вот вызовом t.interrupt() ожидание на мониторе прерывается.

Хорошо, предположим, есть класс:
Код

public class MyRunnable implements Runnable {
    private Thread handler;
    ...
    // seters/geters/run()
}

В чем тогда ощутимое преимущество
Код

Runnable myRunnable = new MyRunnable();
Thread t = new Thread(myRunnable, "My thread");
t.start();
t.join();

перед
Код

MyRunnable myRunnable = new MyRunnable();
myRunnable.setHandler(new Thread(myRunnable,  "My thread"));
myRunnable.getHandler().start();
myRunnable.getHandler().join();
?

Управляющий поток, по сути, один и тот же. Просто во-втором случае ссылка на него хранится в самом объекте, что удобно. Или что-то здесь не так?  smile 

Это сообщение отредактировал(а) nc30 - 22.9.2010, 18:56
PM MAIL   Вверх
LSD
Дата 22.9.2010, 20:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата(nc30 @  22.9.2010,  18:15 Найти цитируемый пост)
В чем тогда ощутимое преимущество

В том что MyRunnable может быть унаследован от любого класса.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
nc30
Дата 23.9.2010, 07:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Интересующийся :)
*


Профиль
Группа: Участник
Сообщений: 140
Регистрация: 24.6.2010
Где: Санкт-Петербург

Репутация: 5
Всего: 8



LSDSkipy
Да не вменятся мне мои посты в полемику с метрами программирования, просто действительно хочу разобраться  smile 
Цитата(LSD @ 22.9.2010,  18:08)
В том что MyRunnable может быть унаследован от любого класса.

В примере выше, и в том, и в другом случае MyRunnable - один и тот же класс, он не наследует от Thread, а реализует интерфейс Runnable.

Вопрос был несколько в другом. Skipy отметил следующее:
Цитата(Skipy @ 22.9.2010,  14:52)

Допустим, Вы создали реализацию Runnable, и Вам необходимо иметь возможность вызывать у нее какие-то методы. Т.е. Вам нужно сохранить ссылку на экземпляр этой реализации.  С другой стороны, Вам нужно иметь ссылку на поток, в котором этот экземпляр работает. Т.е. ссылок получается уже две, вп римере выше - это myRunnable и t. Вот чтобы не хранить две ссылки и не протаскивать их везде, где они нужны, можно унаследовать класс от Thread (а не от Runnable), и тогда ссылка нужна будет всего одна.

По логике поставленной передо мной задачи:
1) неудобно наследоваться от Thread;
2) неудобно хранить две ссылки и протаскивать их везде, где они нужны;
3) тем не менее иметь доступ к основному объекту и управляющему потоку.

Что мне мешает сделать ссылку на управляющий тред в самом классе (см. мой последний пост) и управлять моим потоком через эту ссылку? 
В этом случае хранить и протаскивать (по отношению к основному объекту) нужно будет только ссылку на MyRunnable, и я, по идее, избегаю вышеперечисленных неприятностей.
PM MAIL   Вверх
Skipy
Дата 23.9.2010, 09:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 6
Всего: 16



Цитата(nc30 @ 22.9.2010,  17:15)
В чем тогда ощутимое преимущество

В философии. Как только Вы открыли setHandler - его может использовать кто угодно. Не разобравшись, поставит туда другой поток. Кроме того, Можно вызвать getHandler до того, как будет вызван setHandler. Всё это лишние потенциальные проблемы.

Если Вам неудобно наследоваться от Thread, но нужно иметь его экземпляр - хранение handler-а в самом Runnable есть хороший вариант. Я бы все-таки тогда сделал так:

Код
public class MyRunnable implements Runnable{

  private Thread handler = null;

  public void run(){
    handler = Thread.currentThread();
    // остальной код
  }

  public Thread getHandler(){
    if (handler == null)
      throw new IllegalStateException("You can get handler only from running thread!");
    return handler;
  }
}


Это лучше хотя бы тем, что Вы не светите set-метод, во-первых, и не позовете get-метод до инициализации handler-а во-вторых. 


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
nc30
Дата 23.9.2010, 10:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Интересующийся :)
*


Профиль
Группа: Участник
Сообщений: 140
Регистрация: 24.6.2010
Где: Санкт-Петербург

Репутация: 5
Всего: 8



Skipy, позволю себе еще уточнение. Какие минусы вы видите в следующей реализации?
Код

public class ThreadRunnable implements Runnable {
    private Thread handler;

    public ThreadRunnable() {
        handler = new Thread(this, "ThreadRunnable");
    }

    @Override
    public void run() {
        System.out.println("Hello from " + handler.getName());
    }

    public Thread getHandler() {
        return handler;
    }
}

Что меня привлекло в этом варианте:
1) Управляющий поток создается одновременно с основным объектом. Т. о. нет риска вызвать getHandler() до создания самого handler'а.
2) После создания потока (но перед его стартом) мы можем с ним проделать какие-то подготовительные действия (obj.getHandler().setPriority(), например).
3) Метод setHandler() действительно не нужен "во избежание" (в примере выше он использован для "похожести" наших ситуаций), здесь я с вами полностью согласен.

Это сообщение отредактировал(а) nc30 - 23.9.2010, 10:07
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1350 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.