Vlákna v Jave? – Java – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Vlákna v Jave? – Java – Fórum – Programujte.comVlákna v Jave? – Java – Fórum – Programujte.com

 

wokena0
Stálý člen
22. 7. 2009   #1
-
0
-

Zdravím,
chtěl bych se zeptat, na co se v Jave běžně používají vlákna.Připadá mi, že všechno se dá obejít i bez vláken, můžete mi rozebrat nějakou situaci, kdy se bez vláken obejít nedá?Děkuji za vysvětlení

Nahlásit jako SPAM
IP: 78.102.188.–
md5-generator.wokena.com | blog.wokena.com | wokena.com
Foowie0
Newbie
22. 7. 2009   #2
-
0
-

Napříkad Swing běží celý "v samostatném vlákně" oproti "jádru programu". Pokud by jsi dělal serverovou aplikaci, která komunikuje pomocí socketů a nepoužívá NIO, tak komunikace s každým klientem běží v samostatném vlákně. Pokud bys chtěl využít naplno svůj vícejádrový procesor, tak asi musíš vytvořit více vláken. (teda pokud si to java neumí nějak ošéfovat sama .)
Ono by ses bez vláken i obešel, ale buď by to bylo nepřehlednější, nebo bys zjistil, že vpodstatě simuluješ multithreading. (nebo jsi přišel na efektivnější metodu řešení daného problému, ve kterém nepotřebuješ více vláken)

Nahlásit jako SPAM
IP: 62.129.36.–
wokena0
Stálý člen
22. 7. 2009   #3
-
0
-

Víš, ono je to tak: já jsem se k vláknům dostal právě přez ty sokety :smile1: .A pořád je nemůžu pochopit, resp. umím vytvořit vlákno několika způsoby (tzn. vlákno si vytvořím), ale neumím ho použít tak, jak bych chtěl :smile11: .Zkrátka nechápu, v čem je vlákno efektivnější...
Četl jsem o vláknech v pár knížkách (Java kuchařka programátora, Java 6 výukový kurz...), ale ani jednou jsem jejich smysl nepochopil...

A v knížkách jsou často kapitoly o vláknech (v knížkách) uvozované tím, že v OS jede více programů najednou, a že je to výhodné, ale já jsem slyšel, že když mám třeba 2 vlákna a když jedno třeba přehrává hudbu a druhé piše "ahoj", tak se procesor může přidělit pouze jednomu vláknu a druhé musí čekt, tím pádem by se třeba (podle mě) 20x vypsalo "ahoj", poté přehrál celý zvukový soubor a pak by se zase pokračovalo ve vypisování, co je na tom pravy? Děkuji za vyjasnění...

Nahlásit jako SPAM
IP: 88.100.165.–
md5-generator.wokena.com | blog.wokena.com | wokena.com
Foowie0
Newbie
22. 7. 2009   #4
-
0
-

Pokud máš v programu více procesů, tak OS "sám" rozhodne, kolik procesorového času vlákno dostane. Částečně máš pravdu v tom, že procesor může zpracovávat najednou jenom jedno vlákno (u single-core) (ahoj, nebo hudbu), ale přepíná zpracovávání úloh tak často, že to nevidíš. Např 10ms vypisuje ahoj, pak 10ms posílá hudbu do zvukovky, pak si dělá svoje a pak zase dokola.
Je to jako kdybys měl spuštěné 2 aplikace, jenom je to v jedné :p Jedou obě a nepoznáš že vlastně jede každá chvilku.
Ty jako programátor si teda vytvoříš 2 vlákna (například první, které bude stahovat soubor z internetu, druhé, které bude do konzole vypisovat kolik už je stáhnuto) a ony si fičí pro tebe jakoby paralelně.

Něco jako
vlákno 1:

cyklus dokud nestáhnuto {

buffer = stahni_1kb_z_internetu();
zapis_na_disk(buffer);
ulozeno += 1;
}

vlákno 2:
cyklus {

ulozeno = vlakno1.getUlozeno();
vypis(ulozeno);
pipni();
spi(1sec);
}


Výše máš imaginární příklad toho ukládání s tím, že ti to co sekundu ještě pípne. Kdyby to bylo v jednom vlákně, tak by se mohlo stát, že se ti zasekne internet a program se zabrzdí na řádku "buffer = stahni_1kb_z_internetu();". Mohlo by se to tam klidně seknout na půl hodiny (pokud tě provider nemá rád :p) a nepípalo by ti to. Když máš program v 1. vlákně a "gui" ve druhém, tak se ti nestane, že by ti zamrzlo a nepípalo :p
Edit: kdybys pak chtěl najednou stahovat více souborů, tak jenom vytvoříš více vláken podle vlákna1 a v "gui" vlákně pak jenom zjišťuješ, jak jsou na tom stahování a dáváš informace uživateli, který je stejně afk :)

Nahlásit jako SPAM
IP: 62.129.36.–
wokena0
Stálý člen
22. 7. 2009   #5
-
0
-

Strašně moc ti děkuju za objasnění a za vtipy :smile5: .Jsem rád, že jsi mi to vyložil po tvém.Je to lepší, než hltat stránky "tupého textu v učebncích".Jóó, konečně to cháápu!! :smile18:

Edit:Zkusil jsem si udělat jednoduchý program, který přehrává hudbu v jednom vláknu a v druhém vypisuje text a výsledek je takový, že to opravdu (!!!) přehrává a vypisuje text.

Nahlásit jako SPAM
IP: 88.100.165.–
md5-generator.wokena.com | blog.wokena.com | wokena.com
Foowie0
Newbie
22. 7. 2009   #6
-
0
-

np .) btw ...
Ale vlákna ti při relativně složitějších konstrukcích můžou pěkně zavařit, pokud nepoužíváš správně synchronizační bloky / máš špatný návrh (ikdyž, java je na tom ještě relativně dobře :D) ... jenom takový nástin, kde může nastat problém

vlákno 1:

mám proměnnou X = 0;

zvysX() {
1) temp = X;
2) temp = temp + 6;
3) X = temp;
}

run() {
zvysX();
}


vlákno 2:
run() {

vlakno1.zvysX();
}


Pokud proběhne nejdříve vlákno 1 a pak 2 (nebo naopak, ale postupně), tak po skončení je v proměnné X 12. Pokud ale (náhoda je svině :p) proběhnou "téměř současně", tak výsledek bude 6. Sice je to šance jako že do tebe udeří blesk, ale když už se to stane, tak je z toho průser. Howto? :
vlákno 1 dojde řekněme až k bodu 1) metody zvysX. čili bude v tempu hodnota 0. Pak si operační systém řekne, že tohle vlákno běželo už dost dlouho a pošle ho k ledu a dá šanci běžet vláknu 2. Vlákno 2 se dostane taky do metody zvysX (jinak se tomu říká kritická sekce) a normálně provede ... čili zatím je v proměnné X hodnota 6. Doba ledová skončila a vlákno 1 zase dostalo trochu času pracovat a jelikož má v proměnné temp hodnotu 0, po provedení příkazu 2) bude v tempu 6 a po příkazu 3) bude v X zase 6... a tady je ten průser :)
Když dáš před tu metodu klíčové slovo synchronized, tak v jakékoliv metodě toho objektu může být maximálně najednou jenom jedno vlákno a tahle nešťastná událost se nemůže stát :]

Nahlásit jako SPAM
IP: 62.129.36.–
wokena0
Stálý člen
22. 7. 2009   #7
-
0
-

HH, díky za informaci, ale tohle už vím (jak jsem psal poprvé - četl jsem články z knížek...).Ale nevadí, dděkuji, že jsi mi to chtěl ješe více objasnit, potřeboval jsem vědět jenom samotný pricncip.Když už jsme u toho tvého (výborného) vysvětlování na příkladech, nemohl by jsi mi objasnit metody wait,notify a notifyAll?Já jsem totiž zkoušel pustit příklad z učebnice na wait/notify a když jsem potom vymazal z toho příkladu (programu) wait/notify, tak šel program stejně...

Takže, zjistit, kdy vlákno začne se svou činností zjistit nejde...
Děkuji a těším se na další vysvětlení ;P

Nahlásit jako SPAM
IP: 88.100.165.–
md5-generator.wokena.com | blog.wokena.com | wokena.com
Foowie0
Newbie
23. 7. 2009   #8
-
0
-

Hum ... wait/notify/notifyAll jsou prostředky pro synchronizaci vláken. (Pomocí nich se můžou řešit ipc problémy).
Představ si, že máš na sobě dvě nezávislé jednotky. Výrobce a odběratele. Jsou to socky a mají malý mezisklad, do kterého se vejde jenom jeden výrobek :p. Oba dva jsou reprezentováni svojim vláknem a sklad objektem.

Sklad

třída skladiště {

proměnná vyrobek;
synchronized uložVýrobek() {
while je ve skladu starý výrobek
wait();
dej do skladu nový výrobek;
notifyAll();
}
synchronized vyberVýrobek() {
while sklad je empty
wait();
vybrakuj sklad;
notifyAll();
}
}

Metodu uložVýrobek volá dodavatel, když udělal nějaký výrobek a potřebuje se ho zbavit. Tak hold zavolá metodu. Je synchronized, to zaručuje že je sklad v tu chvíli jenom jeho :p Mrkne dovnitř a pokud je sklad plný, dá si dvacet. (waituje) Pokud ho někdo probudí pomocí notify|all mrkne znovu, jestli si z něho někdo nedělá prdel a pokud ne, odlepí se od židle a nacpe svůj výrobek teda do skladu. (a jde na další směnu)... teda ale ještě předtím probudí všechny kolem (notifyAll) že se něco změnilo ať si to omrknou.
Pokud je někdo ve stavu ležícím/spícím (má wait v synchronized bloku), tváří se ten blok jako kdyby nebyl obsazený žádným vláknem a pustí další vlákno, odběratele. Ten nelení a jde vybrakovat sklad pomocí vyberVýrobek. Nejdříve si zjistí, jeslti tam vůbec něco je, pokud ne, jde spát a čeká až ho někdo vzbudí. Pokud tam něco je, ukradne to a vzbudí všechny kolem (notifyAll), aby mu to tam znovu naplnili. Nejsem si jist, ale myslím, že notify|all musí být poslední příkaz před returnem, aby se mohl uvolnit synchronizovaný blok a mohlo naběhnout další vlákno.
V tomhle příkladu se tedy používá wait|notify|notifyAll aby se nikdo nesnažil dát do skladu více než jeden výrobek a vybrat více než v něm je :) Je to vpodstatě náhražka za "while(je sklad empty);", ale nedráždí to tak procesor :D ... (a while(jeskladempty) by se stejně nedal v synchronizovaném bloku dobře použít, protože by se tam nikdo jiný nedostal)
Ručně a stručně, pokud vlákno zavolá v synchronizovaném bloku wait, bude tam tak dlouho, dokud jiné vlákno v bloku synchronizovaném na stejnou proměnnou nezavolá notify|All .)

Nahlásit jako SPAM
IP: 62.129.36.–
wokena0
Stálý člen
23. 7. 2009   #9
-
0
-

Táák, podle tvého návodu jsem si zkusil udělat program v Jave - a ejhle program háže chybu
výstup:



Exception in thread "main" java.lang.IllegalMonitorStateException
Metoda ulozVyrobek: vyrobek ulozen
at java.lang.Object.notifyAll(Native Method)
at vlakna.Main.uložVýrobek(Main.java:29)
at vlakna.Main.main(Main.java:50)
Java Result: 1


program je zde:


package vlakna;

import java.util.ArrayList;
import java.util.List;

public class Main extends Thread {

static Object vyrobek;
static List l = new ArrayList();

synchronized static void uložVýrobek() throws Exception {

while (!l.isEmpty()) {

Thread.currentThread().wait();
System.out.println("Metod ulozVyrobek: cekam");
}

l.add(vyrobek);
System.out.println("Metoda ulozVyrobek: vyrobek ulozen");
Thread.currentThread().notifyAll();

}

synchronized static void vyberVýrobek() throws Exception {

while (l.isEmpty()) {
Thread.currentThread().wait();
System.out.println("Metoda vyberVyrobek: cekam");
}

l.removeAll(l);
System.out.println("Metoda vyberVyrobek: vybrano");
Thread.currentThread().notifyAll();

}

public static void main(String[] args) throws Exception {
Main.uložVýrobek();
Main.vyberVýrobek();
}
}

Kdyby jsi mi řekl, proč mi to nejede, byl bych Ti vděčný ;P

Nahlásit jako SPAM
IP: 88.100.165.–
md5-generator.wokena.com | blog.wokena.com | wokena.com
Foowie0
Newbie
23. 7. 2009   #10
-
0
-

Tady to máš fungující:

class Sklad {

protected String vyrobek;

public Sklad() {
vyrobek = null;
}

synchronized void ulozVyrobek(String vyrobek) throws InterruptedException {
while( !skladJeVolny() )
wait();
this.vyrobek = vyrobek;
notifyAll();
}

synchronized String vyberVyrobek() throws InterruptedException {
while( skladJeVolny() )
wait();
String temp = vyrobek;
vyrobek = null;
notifyAll();
return temp;
}

synchronized boolean skladJeVolny() {
return (vyrobek == null);
}
}

class Producent extends Thread {
protected Sklad sklad;

public Producent(Sklad sklad) {
this.sklad = sklad;
}

@Override
public void run() {
for(int i = 0; i < 10; i++) {
try {
sleep(1000); // Producentovi celkem trvá než udělá nový výrobek
System.out.println("Producent: pokouším se uložit výrobek '" + i + "'...");
sklad.ulozVyrobek(Integer.toString(i));
System.out.println("Producent: uložil výrobek '" + i + "'");
} catch (InterruptedException ex) {
System.out.println(ex);
ex.printStackTrace();
}
}
}
}

class Konzument extends Thread {
protected Sklad sklad;

public Konzument(Sklad sklad) {
this.sklad = sklad;
}

@Override
public void run() {
for(int i = 0; i < 10; i++) {
try {
sleep(100); // Konzument výrobek zpracuje rychle
System.out.println("Konzument: pokouším se vybrat výrobek...");
String vyrobek = sklad.vyberVyrobek();
System.out.println("Konzument: vybral výrobek '" + vyrobek + "'");
} catch (InterruptedException ex) {
System.out.println(ex);
ex.printStackTrace();
}
}
}
}

class Main {
public static void main(String[] args) {
Sklad sklad = new Sklad();
Thread producent = new Producent(sklad);
Thread konzument = new Konzument(sklad);
producent.start();
konzument.start();
}
}


Nechce se mi detailně zkoumat, proč to tvoje nejede, ale jenom tak od oka: vůbec nevytváříš více vláken a nevím, jestli wait/notify je dobré používat ve statických metodách :) ... a co ta čeština ve jménech metod ?!? :D

Nahlásit jako SPAM
IP: 62.129.36.–
wokena0
Stálý člen
23. 7. 2009   #11
-
0
-

Říkal jsem, že jsem to zkopčil od tebe :D
Jinak, díky za funkční příklad ;P

Edit:Zkusil jsem si trochu zaexperimentovat s tvým programem a zjistil jsem, že, když v programu nejsou metody Thread.sleep(), tak, že program nejede tak, jako s němi, zajímalo by mě, proč...

Nahlásit jako SPAM
IP: 88.100.165.–
md5-generator.wokena.com | blog.wokena.com | wokena.com
Foowie0
Newbie
23. 7. 2009   #12
-
0
-

Bez Thread.sleep() :

Producent: pokouším se uložit výrobek '0'...

Producent: uložil výrobek '0'
Producent: pokouším se uložit výrobek '1'...
Konzument: pokouším se vybrat výrobek...
Konzument: vybral výrobek '0'
Konzument: pokouším se vybrat výrobek...
Producent: uložil výrobek '1'
Producent: pokouším se uložit výrobek '2'...
Konzument: vybral výrobek '1'
Konzument: pokouším se vybrat výrobek...
Producent: uložil výrobek '2'
Producent: pokouším se uložit výrobek '3'...
Konzument: vybral výrobek '2'
Konzument: pokouším se vybrat výrobek...
Konzument: vybral výrobek '3'
Konzument: pokouším se vybrat výrobek...
Producent: uložil výrobek '3'
Producent: pokouším se uložit výrobek '4'...
Producent: uložil výrobek '4'
Producent: pokouším se uložit výrobek '5'...
Konzument: vybral výrobek '4'
Konzument: pokouším se vybrat výrobek...
Producent: uložil výrobek '5'
Producent: pokouším se uložit výrobek '6'...
Konzument: vybral výrobek '5'
Konzument: pokouším se vybrat výrobek...
Producent: uložil výrobek '6'
Producent: pokouším se uložit výrobek '7'...
Producent: uložil výrobek '7'
Producent: pokouším se uložit výrobek '8'...
Konzument: vybral výrobek '6'
Konzument: pokouším se vybrat výrobek...
Konzument: vybral výrobek '7'
Konzument: pokouším se vybrat výrobek...
Producent: uložil výrobek '8'
Producent: pokouším se uložit výrobek '9'...
Konzument: vybral výrobek '8'
Konzument: pokouším se vybrat výrobek...
Producent: uložil výrobek '9'
Konzument: vybral výrobek '9'

Podle "logu" vypadá že je vše v pořádku. Nikdy konzument nevybere zásilku dříve, než tam nějaká je a nikdy producent nevloží zásilku do skladu, dokud je plný (s tím, že po tom co jí tam producent dá jí konzument okamžitě vybere...je hned probuzen a naopak). Jeslti se producent "pokusí vložit" výrobek předtím, než konzument vybere spátky nezáleží, to je tam jenom pro info. On se producent zasekne práve na tom waitu. Důležitá je ta informace uložil/vybral... Pokud tam nemáš ten sleep, tak každý log může vypadat jinak, protože operační systém může nechat běžet vlákna "různě dlouho v různém pořadí" a proto se někdy producent pokusí vložit výrobek ikdyž tam je (vlákno má více procesorového času) a někdy ne (bylo skončeno před pokusem).
Jedu na Vltavu, takže další odpověď čekej tak za týden :p

EDIT: Tak se dívám že jsem se blbě podíval a v ten log nevypadá nejlépe, ale asi to je tím, že ty výpisové hlášky nejsou v tom synchronized bloku ulozVyrobek / vyberVýrobek. Tím pádem OS může to vlákno vypnout ještě předtím, než to vypíše na obrazovku (a druhé se tam s klidem dostane) a pak to vypadá zmateně :) Skus je tam dát :)

Nahlásit jako SPAM
IP: 62.129.36.–
wokena0
Stálý člen
23. 7. 2009   #13
-
0
-

Moc děkuju, příjemnou dovolenou :P

Nahlásit jako SPAM
IP: 88.100.165.–
md5-generator.wokena.com | blog.wokena.com | wokena.com
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 29 hostů

Podobná vlákna

JPA + vlákna + transakce v javě SE — založil Arnold Judas Rimmer

Vlákna — založil blackman.ce

Vlákna — založil Tayson

Vlakna — založil insider

Vlakna — založil insider

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý