Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Потоки и передача в них параметров

244
19 января 2011 года
UAS
2.0K / / 19.07.2006
Решил тут, дабы освежить память и чуть набраться опыта, вновь попрограммировать в Java. Собственно, что огорчило в потоках, так это то, что на выполнение можно запускать только через метод run и параметров в него передать нельзя (после C# такой подход к организации потоков мне крайне непонятен).
Опишу задачу:
Хочу написать парсер для собственных целей - стягивает с сайта список новых альбомов, после чего я могу выбрать необходимые для загрузки. Естественно, будет гуишка с прогресс барами и прочими свистелками.

Собственно, логически программа делиться на след.части:
1) Загрузка веб-страницы, парсинг списка альбомов с их описанием
2) Формирование пакета задач для даунлоадера либо непосредственная скачка.
Хочется каждую из этих задач вынести в отдельный метод, причем каждый такой метод будет выполняться в отдельном потоке.
Как я понял, после прочтения мана и листания учебника, Java не позволяет запустить на выполнение произвольный метод, а также не позволяет передать параметры в метод run. Вопрос - как поступить?

Просто я не вижу смысла создавать два разных класса.
Есть вариант создать какой-либо атрибут класса, который будет определять, какую операцию запускать, но мне это кажется каким-то костылем.

Собственно, кто посоветует как лучше организовать и как это принято в яве?
512
19 января 2011 года
bnm
124 / / 17.10.2004
Цитата: UAS
Как я понял, после прочтения мана и листания учебника, Java не позволяет запустить на выполнение произвольный метод, а также не позволяет передать параметры в метод run.


Что значит "Java не позволяет запустить на выполнение произвольный метод"? Т.е. ты в классе не можешь вызвать метод который в нем определен?) Если ты про вызов без экземпляра , то метод должен объявляться как статик.
Зачем в ран передавать параметры, когда это делается через сеттеры?

Цитата: UAS
Просто я не вижу смысла создавать два разных класса.


ИМХО в твоем случае, выполнение 1)2) в одном потоке, есть самый натуральный костыль..)

244
19 января 2011 года
UAS
2.0K / / 19.07.2006
Вопрос снят, малость потупил-потупил, но разобрался во всем и сделал выводы.
5
19 января 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: bnm

Зачем в ран передавать параметры, когда это делается через сеттеры?

Это потому что в Java нет замыканий (уж который год грозятся, а никак разодиться не могут).

355
20 января 2011 года
<SCORP>
786 / / 21.10.2006
Цитата: hardcase
Это потому что в Java нет замыканий (уж который год грозятся, а никак разодиться не могут).



та и хвала богам!

5
20 января 2011 года
hardcase
4.5K / / 09.08.2005
[QUOTE=<SCORP>;342705]та и хвала богам![/QUOTE]
А что в них плохого?
63
20 января 2011 года
Zorkus
2.6K / / 04.11.2006
Цитата: hardcase
Это потому что в Java нет замыканий (уж который год грозятся, а никак разодиться не могут).


Они формально есть (в виде анонимных и локальных классов), read-only доступ к контексту + аццкий синтаксис.

Вот в Groovy есть :) Пишите на Groovy.

355
20 января 2011 года
&lt;SCORP&gt;
786 / / 21.10.2006
плохого - да в общем-то ничего кроме усложнения языка. и пользы кроме усложнения языка я тоже не вижу
5
20 января 2011 года
hardcase
4.5K / / 09.08.2005
[QUOTE=<SCORP>;342717]плохого - да в общем-то ничего кроме усложнения языка. и пользы кроме усложнения языка я тоже не вижу[/QUOTE]
Рациональное зерно в твоих словах есть. Это действительно очень большая пушка для тех, кто практикует MDD - Monkey Driven Development.
63
20 января 2011 года
Zorkus
2.6K / / 04.11.2006
[QUOTE=<SCORP>;342717]плохого - да в общем-то ничего кроме усложнения языка. и пользы кроме усложнения языка я тоже не вижу[/QUOTE]

Я это где-то уже слышал. Парадокс Блаба, трясина Тьюринга - все это относится сюда.

Польза от полноценных замыканий поддерживаемых на уровне языка несомненная для тех, кто их пробовал.

Сравни два куска кода:

Java -
 
Код:
interface ResourceUser {
   void use(Resource resource)
}
resourceHandler.handle(new ResourceUser(){
   public void use (Resource resource) {
      resource.doSomething()
   }
});


и Groovy

 
Код:
resourceHandler.handle { resource -> resource.doSomething() }


Разница в выразительности есть?
5
20 января 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Zorkus

Разница в выразительности есть?


Это не замыкание. Это ты лямбду сделал.
Замыканием будет видимо так:

Код:
interface ResourceUser {
   void use(Resource resource)
}

int param1 = getParamValueFromAnywhere(); // затратная и долгая операция
resourceHandler.handle(new ResourceUser(param1){
   public ResourceUser(int param1) { this.param1 = param1; }
   private int param1;
   public void use (Resource resource) {
      resource.doSomething(param1)
   }
});


И с замыканием:
 
Код:
int param1 = getParamValueFromAnywhere(); // затратная и долгая операция
resourceHandler.handle { resource -> resource.doSomething(param1) }



(PS в Java ни в зуб-ногой)
244
20 января 2011 года
UAS
2.0K / / 19.07.2006
Немного оффтопа. Ява вообще почему-то меня расстраивает как раз тем, что для записи каких-нибудь очевидных вещей необходимо писать килобайты кода, когда в других языках это все решается гораздно более меньшим кодом и более очевидно и наглядно (например, пример от Zorkus).
355
20 января 2011 года
&lt;SCORP&gt;
786 / / 21.10.2006
Цитата: hardcase
Это не замыкание. Это ты лямбду сделал.
Замыканием будет видимо так:
Код:
interface ResourceUser {
   void use(Resource resource)
}

int param1 = getParamValueFromAnywhere(); // затратная и долгая операция
resourceHandler.handle(new ResourceUser(param1){
   public ResourceUser(int param1) { this.param1 = param1; }
   private int param1;
   public void use (Resource resource) {
      resource.doSomething(param1)
   }
});



код на Java работать не будет - Java не позволяет объявлять конструкторы для анонимных классов

 
Код:
interface ResourceUser {
   void use(Resource resource)
}

final int param1 = getParamValueFromAnywhere(); // затратная и долгая операция
resourceHandler.handle(new ResourceUser(param1){
   public void use (Resource resource) {
      resource.doSomething(param1)
   }
});

будет работать вот так

принципиальной разницы не вижу. в лямбду в сообщении Zorkus"а долго втыкал (может я просто не привычный к таким вещам - пару лет кроме Java ни на чём не пишу почти). да, кода больше. зато он просто и прозрачен на 100%. кода много - но его ведь руками сегодня уже не писать - современный среды разработки делают это за тебя. а читается, ИМО, куда проще
63
20 января 2011 года
Zorkus
2.6K / / 04.11.2006
Цитата: hardcase
Это не замыкание. Это ты лямбду сделал.



Да, сорри, просто в груви эти слова используются как синонимы почему-то. Пример с замыканием должен включать в себя анонимный класс в яве, который использует, скажем, локальную переменную из метода, где этот самый класс объявляется.

5
20 января 2011 года
hardcase
4.5K / / 09.08.2005
[QUOTE=<SCORP>;342729]
 
Код:
interface ResourceUser {
   void use(Resource resource)
}

final int param1 = getParamValueFromAnywhere(); // затратная и долгая операция
resourceHandler.handle(new ResourceUser(param1){
   public void use (Resource resource) {
      resource.doSomething(param1)
   }
});

будет работать вот так[/QUOTE]Спасибо. Это, собственно, и есть замыкание - захват переменных из лексического контекста. В Java нету лямбд - вместо них приходится создавать реализации интерфейсов, что приводит к некислому синтаксическому оверхеду из-за того, что лямбды обычно содержат минимум кода - вызов одного-двух методов либо операторов - что на фоне всего присущего реализации целого интерфейса (прописывания полных сигнатур методов с именами), конечно, не слишком красиво выглядит.
355
20 января 2011 года
&lt;SCORP&gt;
786 / / 21.10.2006
а по-моему не более чем непривычно. т.е. по сути в Java это всё уже есть. просто выглядит подругому, да немного более громоздко. но зачем делать ещё один способ сделать то же самое?
а если у меня будет какой-то вызов сделан с помощью лямбда-выражения (одна строчка, да?) и мне вдруг понадобиться расширить это дело до 3-5 строк, напр. как здесь быть? переписывать таки на анонимный класс?
5
20 января 2011 года
hardcase
4.5K / / 09.08.2005
[QUOTE=<SCORP>;342737]а если у меня будет какой-то вызов сделан с помощью лямбда-выражения (одна строчка, да?) и мне вдруг понадобиться расширить это дело до 3-5 строк, напр. как здесь быть? переписывать таки на анонимный класс?[/QUOTE]Зависит от :) Лямбду можно и на несколько строк растянуть, но это нужно редко и как правило весь рефакторинг лямбды сводится к выбрасыванию из кода либо замене ее тела на что-то другое - такое же лаконичное.
244
26 января 2011 года
UAS
2.0K / / 19.07.2006
Собственно, опять заработал себе баттхерт с этими потоками. Дабы не создавать новую тему - спрошу здесь.
Проблемы как таковой нету, я лишь хочу показать алгоритм взаимодействия потоков и прошу подсказать - верно или нет. Т.е. верно ли я подхожу к задаче в рамках Явы или можно все сделать намного проще?

Задача: распарсить отпределенное кол-во страниц и получить с них данные (на данном этапе только один тип страниц, в будущем будет несколько, но все в рамках одного сайта).
Как должно выглядеть: гуишка, из которой запускается процесс парсинга + различные параметры, описывающий процесс (прогресс бар, текущая страница в парсинге и т.д.)

Как сейчас все выглядит (в общем виде):
1)
Класс ParserAlbumList, содержащий статический метод ArrayList<E> parseAlbumList(String url) - собственно парсит конкретный url, возвращает результат в виде ArrayList.

2) Класс mp1Worker - ему передается массив url-для парсинга, каждая из которых передается в parseAlbumList. Должен иметь поля доступа к инфе (т.е. какая в данный момент страница парсится, описание текущего процесса) + данный класс в будущем будет парсить разные типы страниц. Реализует интерфейс Runnable.
Краткий код её (без подробностей):
Код:
public class Mp1Worker implements Runnable {
    public enum WorkMode { NONE, PARSE_ALBUMS_LIST }
    public WorkMode mode = WorkMode.NONE;

    public void run() {
        switch(mode) {
            case PARSE_ALBUMS_LIST: parseAlbumsList(); break;
            ...
        }
    }


    public String[] pagesToParse;            // страницы для парсинга (url-ки)
    public ArrayList<E> parsedAlbumsList; // результат парсинга
    public int currentParsingPage = -1;    // текущая парсируемая страница

    public void parseAlbumsList() {
        ...
        for(currentParsingPage = 0; ....)
            ArrayList<E> result = ParserAlbumsList.parseAlbumsList(pagesToParse); // парсим
            ... // обработка результатов, созранение промежуточной инфы и т.д.
    }
}


3) Собственно, формочка GUI-шная для запуска процесса.
Я так понимаю, что процесс обновления инфы надо запускать в отдельном потоке, дабы не "вешать форму". Т.е. минимум должно быть два потока:
1) Поток, выоплняющий парсинг списка страниц
2) Поток, отслежвающий процесс парсинга, реализует обновление прогресс-бара

Значит, код клика по кнопке (допустим) будет типа:
Код:
Mp1Worker mp1 = new Mp1Worker;
Thread t_mp1 = new Thread(mp1);

mp1.mode = Mp1Worker.WorkMode.PARSE_ALBUMS_LIST;
mp1.pagesToParse = new String[] { ... }

// тут создание экземпляра класса, реализующего процесс обновления
Upd u = new Upd();
Thread t_u = new Thread(u);
u.progressBar = mainForm.ProgressBar; // типа присвоение указателя на прогресс бар на этой форме
u.mp1 = mp1; // ссылка на парсер

mp1.Start();
u.Start();


Т.е. корректная работа будет примерно вот такая? Или все делается намного проще и очевиднее? Просьба знающих подсказать, дабы сразу не путаться мне в изучении.
1.8K
26 января 2011 года
LM(AL/M)
332 / / 20.12.2005
по моему отдельный поток для апдейта прогрессбара не нужен. Вместо этого достаточно реализовать механизм извещения о завершении очередного куска работы (что-то вроде метода OnPageParsed который вызовет соответствующий делегат, не буду пока вдаваться в подробности), иными словами реализовать паттерн Наблюдатель.

а вообще сдается мне подход изначально неверный. тут видна попытка решить сразу много разнотипных задач и в итоге получается мешанина какая-то. я бы например не стал реализовывать Mp1Worker как Runnable и вместо mp1.Start(); написал бы в соответствующем месте
 
Код:
new Thread(new Runnable(){
        public void run() {
             mpl.parseAlbumsList();
        }
    }.start();

и таким образом функциональность парсинга можно было бы отладить отдельно от всего (при этом не заботясь ни о каких потоках), например в обычной консольке, а уж потом браться за реализацию GUI
244
26 января 2011 года
UAS
2.0K / / 19.07.2006
LM(AL/M), ага, сам вчера когда спать ложился, подумал, что проще сделать все через Runnable() {...}, чем разворачивать такие классы. Так и поступлю, скорее всего. Ещё бы замыкание было более очевидное, был бы вообще рад, но с этим в целом разобрался)

Цитата:
и таким образом функциональность парсинга можно было бы отладить отдельно от всего (при этом не заботясь ни о каких потоках), например в обычной консольке, а уж потом браться за реализацию GUI


Это уже проверено, тем более я как раз всегда сначала пишу на консольке, а потом гуишки верчу)

276
26 января 2011 года
Rebbit
1.1K / / 01.08.2005
[QUOTE=<SCORP>;342729]
 
Код:
interface ResourceUser {
   void use(Resource resource)
}

final int param1 = getParamValueFromAnywhere(); // затратная и долгая операция
resourceHandler.handle(new ResourceUser([COLOR=Red]param1[/COLOR]){
   public void use (Resource resource) {
      resource.doSomething(param1)
   }
});
будет работать вот так
[/QUOTE]
Маленькая поправка (красное удаляем).
2hardcase
По сути вы правы. С кода приведеного <SCORP>ом компилятор всеровно сделает так как вы написали (неявно). Отсюда и обязательный модификатор final (константа). Так как анонимный клас будет иметь свою копию переменной то сам компилятор заставляет замаркать внешнюю преременную константой чтоб предотвратить недоразумения. А то програмист начнет ее менять, а толку не будет :).
276
26 января 2011 года
Rebbit
1.1K / / 01.08.2005
Цитата: UAS

Хочется каждую из этих задач вынести в отдельный метод, причем каждый такой метод будет выполняться в отдельном потоке.
Как я понял, после прочтения мана и листания учебника, Java не позволяет запустить на выполнение произвольный метод, а также не позволяет передать параметры в метод run. Вопрос - как поступить?

Просто я не вижу смысла создавать два разных класса.
Есть вариант создать какой-либо атрибут класса, который будет определять, какую операцию запускать, но мне это кажется каким-то костылем.



Цитата: UAS
Вопрос снят, малость потупил-потупил, но разобрался во всем и сделал выводы.



Дик я всетаки не понял как вы вышли из положения. Я не вижу иных выходов кроме разних класово имплементящих Runnable/Thread, одного свича для того чтоб запустить разные методы или перегрузки метода в иерархии.

Сам недавно парсер писал и так мне нехватало указателей на методы :).

244
26 января 2011 года
UAS
2.0K / / 19.07.2006
Цитата:
Дик я всетаки не понял как вы вышли из положения. Я не вижу иных выходов кроме разних класово имплементящих Runnable/Thread, одного свича для того чтоб запустить разные методы или перегрузки метода в иерархии.


Так и решил делать. Куча имплементов Runnable + свитчи.

Цитата:
Сам недавно парсер писал и так мне нехватало указателей на методы

Не говори, сам после C# не могу тут привыкнуть к такой системе потоков.

276
26 января 2011 года
Rebbit
1.1K / / 01.08.2005
Один человек предлагал мне юзать рефлексию и доставать метод по названию. Но я уж лутше много кода нипишу чем рефлексию для такого юзать буду.

А про Java - всеровно его не брошу, потому что он хорошый :)
355
26 января 2011 года
&lt;SCORP&gt;
786 / / 21.10.2006
Цитата: Rebbit

Сам недавно парсер писал и так мне нехватало указателей на методы :).



а зачем? есть интерфейсы, есть ссылки на инстанс, реализующий интерфейс - чего ещё надо??

276
26 января 2011 года
Rebbit
1.1K / / 01.08.2005
[QUOTE=<SCORP>;343217]а зачем? есть интерфейсы, есть ссылки на инстанс, реализующий интерфейс - чего ещё надо??[/QUOTE]
Да оно то понятно. Просто скобок {} сильно много. Иногда действительно проще свичем обойтись.
63
26 января 2011 года
Zorkus
2.6K / / 04.11.2006
Цитата: Rebbit
Один человек предлагал мне юзать рефлексию и доставать метод по названию. Но я уж лутше много кода нипишу чем рефлексию для такого юзать буду.

А про Java - всеровно его не брошу, потому что он хорошый :)



А вот так это работает в Groovy.

Код:
public class TestClass{

    public testA(){println 'Called A'}
    public testB(){println 'Called B'}
    public testC(){println 'Called C'}
    public testD(){println 'Called D'}
}

def methodName = 'testA'
TestClass test = new TestClass()
test."$methodName"()

Выводит честное "Called A".
5
26 января 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Zorkus

Выводит честное "Called A".


Позднее связывание?

63
26 января 2011 года
Zorkus
2.6K / / 04.11.2006
Цитата: hardcase
Позднее связывание?


Ну можно сказать и так. В Groovy все вызовы методов роутятся через так называемые метаклассы в виде getMetaclass.invokeMethod(objectRef, method name, params list).

Благодаря чему имя метода можно быть взято из переменной.
http://groovy.codehaus.org/Groovy+Method+Invokation

355
26 января 2011 года
&lt;SCORP&gt;
786 / / 21.10.2006
Цитата: Zorkus
А вот так это работает в Groovy.
...
Выводит честное "Called A".



в PHP оно тоже так работает. и? :)

63
26 января 2011 года
Zorkus
2.6K / / 04.11.2006
[QUOTE=<SCORP>;343237]в PHP оно тоже так работает. и? :)[/QUOTE]
А PHP это компилируемый язык?

Я привел пример кода, который компилится в java bytecode.
276
26 января 2011 года
Rebbit
1.1K / / 01.08.2005
Цитата: Zorkus
Я привел пример кода, который компилится в java bytecode.


Ну и что что компилируется. Всеровно на етапе компиляции проверка правильности входних параметров и типа результата ушла на мороз :).

355
26 января 2011 года
&lt;SCORP&gt;
786 / / 21.10.2006
для PHP это тоже вариант :) http://www.caucho.com/resin-3.0/quercus/
276
26 января 2011 года
Rebbit
1.1K / / 01.08.2005
Груви, РНР фигня все. Вот когда С++ и С# в Джава байткод компилировать начнут вот ето будет вестч. :D
63
26 января 2011 года
Zorkus
2.6K / / 04.11.2006
Цитата: Rebbit
Груви, РНР фигня все. Вот когда С++ и С# в Джава байткод компилировать начнут вот ето будет вестч. :D



Да ты извращенец. Писать на С++ управляемый код под JVM. Потеряйте суперскорость работы, а это как известно, последний серьезный аргумент сишников, и не получите взамен нормального языка. Так? :)

244
27 января 2011 года
UAS
2.0K / / 19.07.2006
Таки да, с использованием анонимных классов все выглядит намного прекраснее и симпатичнее. Так что не все так ужасно и печально, как я представлял =)

Кстати, кому интересно, тут написано про взаимодействие гуишки с другими потоками: http://www.skipy.ru/technics/gui_sync.html#impl_manual
Как человеку, работающему с явой недолгое время - не все понятно с первого раза, но общий принцип организации взаимодействия потоков с использованием интерфейсов становится понятным. В общем, советую.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог