HOJ Säikeet (Java) Ville Leppänen. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.1/55

Samankaltaiset tiedostot
Rinnakkaisohjelmointi kurssi. Opintopiiri työskentelyn raportti

Luento 6. T Ohjelmoinnin jatkokurssi T1 & T Ohjelmoinnin jatkokurssi L1. Luennoitsija: Otto Seppälä

Hajautettujen sovellusten muodostamistekniikat (Java-kielellä), TKO_2014 Aineopinnot, syksy 2009 Turun yliopisto / Tietotekniikka

Projekti 1 Säikeet ja kriittisen vaiheen kontrollointi javalla

Ohjelmoinnin peruskurssien laaja oppimäärä

Rinnakkaisohjelmointi, Syksy 2006

Monitorit -projekti Rinnakkaisohjelmointi

Liite 1. Projektin tulokset (Semaforit Javassa) Jukka Hyvärinen Aleksanteri Aaltonen

812315A Ohjelmiston rakentaminen. Asynkronisuus

HOJ Kertausluento. Ville Leppänen. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.1/58

Javan semaforit. Joel Rybicki, Aleksi Nur mi, Jara Uitto. Helsingin yliopisto

Yleistä. Nyt käsitellään vain taulukko (array), joka on saman tyyppisten muuttujien eli alkioiden (element) kokoelma.

Vertailulauseet. Ehtolausekkeet. Vertailulauseet. Vertailulauseet. if-lauseke. if-lauseke. Javan perusteet 2004

Sisältö. 2. Taulukot. Yleistä. Yleistä

Olio-ohjelmointi Javalla

Tehtävä 1. Tehtävä 2. Arvosteluperusteet Koherentti selitys Koherentti esimerkki

Sisältö. 22. Taulukot. Yleistä. Yleistä

14. Poikkeukset 14.1

Ohjelmointi 2 / 2010 Välikoe / 26.3

Ohjelmointi 2 / 2008 Välikoe / Pöytätestaa seuraava ohjelma.

Mikä yhteyssuhde on?

Sisällys. 14. Poikkeukset. Johdanto. Johdanto

T Henkilökohtainen harjoitus: FASTAXON

Rajapinta (interface)

Rinnakkaisuus. Juha Järvensivu 2008

10 Lock Lock-lause

Sisällys. 14. Poikkeukset. Johdanto. Johdanto

Listarakenne (ArrayList-luokka)

Graafisen käyttöliittymän ohjelmointi Syksy 2013

Java-kielen perusteet

14. Poikkeukset 14.1

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

Olion elinikä. Olion luominen. Olion tuhoutuminen. Olion tuhoutuminen. Kissa rontti = null; rontti = new Kissa();

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op. Poikkeukset ja tietovirrat: Virhetilanteiden ja syötevirtojen käsittely

5/20: Algoritmirakenteita III

Java ja grafiikka. Ville Sundberg

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

Java kahdessa tunnissa. Jyry Suvilehto

RINNAKKAINEN OHJELMOINTI A,

11. Javan valintarakenteet 11.1

Metodien tekeminen Javalla

Ohjelmoinnin peruskurssien laaja oppimäärä

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. X Poikkeusten käsittelystä

7. Oliot ja viitteet 7.1

Javan perusteita. Janne Käki

HOJ RMI = Remote Method Invocation

Luokka Murtoluku uudelleen. Kirjoitetaan luokka Murtoluku uudelleen niin, että murtolukujen sieventäminen on mahdollista.

1. Omat operaatiot 1.1

HSMT Tietokannoista. Ville Leppänen. HSMT, c Ville Leppänen, IT, Turun yliopisto, 2008 p.1/32

JAVA on ohjelmointikieli, mikä on kieliopiltaan hyvin samankaltainen, jopa identtinen mm. C++

Kompositio. Mikä komposition on? Kompositio vs. yhteyssuhde Kompositio Javalla Konstruktorit set-ja get-metodit tostring-metodi Pääohjelma

Poikkeustenkäsittely

Rinnakkaisuus. parallel tietokoneissa rinnakkaisia laskentayksiköitä concurrent asioita tapahtuu yhtaikaa. TTY Ohjelmistotekniikka

Harjoitus Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:

1 Tehtävän kuvaus ja analysointi

Java-kielen perusteita

Luokan sisällä on lista

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

11. Javan toistorakenteet 11.1

12. Javan toistorakenteet 12.1

Ohjelmoinnin jatkokurssi, kurssikoe

Tietokannat II -kurssin harjoitustyö

Jaana Diakite Projekti 1 JAVA-Monitorit 1(13) Rinnakkaisohjelmointi Anu Uusitalo

Metodit Arvotyyppi. Metodit Arvotyyppi. Metodit Parametrit. Metodit Parametrit. Metodit Kuormittaminen. Metodit Kuormittaminen. Javan perusteet

7. Näytölle tulostaminen 7.1

815338A Ohjelmointikielten periaatteet

4. Luento: Prosessit ja säikeets. Tommi Mikkonen,

812341A Olio-ohjelmointi Peruskäsitteet jatkoa

Java-kielen perusteet

Luokat ja oliot. Ville Sundberg

Mitä poikkeuskäsittely tarkoittaa?

Ohjelmointityö 3. Mikko Laamanen

Ehto- ja toistolauseet

12. Javan toistorakenteet 12.1

16. Javan omat luokat 16.1

8. Näppäimistöltä lukeminen 8.1

Semaforit Javassa. Mari Kononow, Eveliina Mattila, Sindi Poikolainen HELSINGIN YLIOPISTO

A) on käytännöllinen ohjelmointitekniikka. = laajennetaan aikaisemmin tehtyjä luokkia (uudelleenkäytettävyys)

Sisältö. Johdanto. Tiedostojen lukeminen. Tiedostojen kirjoittaminen. 6.2

on ohjelmoijan itse tekemä tietotyyppi, joka kuvaa käsitettä

Java-API, rajapinnat, poikkeukset, UML,...

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä

public static void main (String [] args)

Taulukoiden käsittely Javalla

Rinnakkaisuus (.NET) Juha Järvensivu 2007

1.3Lohkorakenne muodostetaan käyttämällä a) puolipistettä b) aaltosulkeita c) BEGIN ja END lausekkeita d) sisennystä

HOJ Haja-aiheita. Ville Leppänen. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.1/10

Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 15.3

Sisältö Johdanto. Tiedostojen lukeminen. Tiedostojen kirjoittaminen. 26.2

Concurrency - Rinnakkaisuus. Group: 9 Joni Laine Juho Vähätalo

Sisällys. 7. Oliot ja viitteet. Olion luominen. Olio Java-kielessä

Muuttujat ja kontrolli. Ville Sundberg

JAVA-OHJELMOINTI 3 op A274615

9. Periytyminen Javassa 9.1

Hajautettujen sovellusten muodostamistekniikat, TKO_2014 Johdatus kurssiin

Ehto- ja toistolauseet

9. Periytyminen Javassa 9.1

Informaatioteknologian laitos Olio-ohjelmoinnin perusteet / Salo

12. Näppäimistöltä lukeminen 12.1

Transkriptio:

HOJ Säikeet (Java) Ville Leppänen HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.1/55

Missä mennään... 1. Johdanto (1h) 2. Säikeet (2h) 3. Samanaikaisuudesta (2h) 4. Hajautetuista sovelluksista (1h) 5. Soketit (3h) 6. RMI ja J2EE (3h) 7. RPC (1h) 8. WWW-sovellustekniikoista (2h) 9. Pilvialustat (4h) 10. Haja-aiheita (2h) 99. Kertausluento (2h) + 1h pelivaraa HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.2/55

Luennosta Yleistä säikeistä Säikeiden elinkaari ja prioriteetit. Säikeiden muodostus Luokka Thread Säikeiden välinen keskustelu Säikeiden välisen yhteistoiminnan koordinointi Tiedon jakaminen säikeiden kesken Esimerkkejä HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.3/55

Yleistä säikeistä 1/4 Tutustuttu jo: tapahtumankäsittelysäie ja main -säie. Voidaan luoda ja käynnistää itse. Säie: peräkkäinen käskyvirta. Samanaikaisuus rinnakkaisuus. Säie prosessi. Monen ongelman ratkaisun ilmaiseminen rinnakkain luonnollista. Koneessa useita prosessoreita = aidosti samanaikaan suoritettavia prosesseja. Kyky reagoida moneen suuntaan. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.4/55

Yleistä säikeistä 2/4 Perustuu työn jakamiseen, mutta seurauksena on usein myös tietojen jakaminen. Javan säikeet jakavat muistiavaruuden. Tiedon käytön koordinointi tärkeää: samanaikainen käyttö voi johtaa ongelmatilanteisiin. Samanaikaisten päivitysten seurauksena ehkä epäkonsistentti tila. Lukeminen: myös ongelmia. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.5/55

Multithreading Sovellus 1 Käyttöjärjestelmä Sovellus 2 Javan JVM Säie 1 paikallinen muisti Säie 2 paikallinen muisti Globaali muisti Säie 3 paikallinen muisti HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.6/55

Yleistä säikeistä 3/4 Lukitsemalla tietorakenteita (olioita) tai estämällä usean säikeen pääsy samanaikaisesti metodiin voidaan ratkaista ongelmia. Mutta... lukitsemisen seurauksena voi tulla syklejä = jumiutuminen. Lisäksi: säikeille annettavaa aikaa pitää jotenkin kontrolloida. Kaikkien pitää saada aikaa, muuten starvation. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.7/55

Lukkiutuminen Aika Säie 1 L1 ottaa lukon L1 L2 odottaa lukkoa L2 Säie 2 L2 ottaa lukon L2 L1 odottaa lukkoa L1 HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.8/55

Yleistä säikeistä 4/4 Käytännön seikkoja: Javaa suoritetaan usein tulkitsemalla. Tulkitseva JVM on yksi koneen KJ:n prosessi. Koneen KJ jakaa aikaa prosessien välillä. Javan säikeitä suoritetaan JVM:n sisällä. JVM:llä on KJ:n prosessien hallintaominaisuudet. (Tilanne on osin muuttunut: mahdollista käyttää useita KJ:n säikeitä.) Ei siis kovin helposti tehoa monesta prosessorista, mutta silti hyödyllistä esim. animoinnissa ja verkkoyhteyksissä. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.9/55

Raita: säikeiden tilat Suorituksen loppuminen normaalisti tai epänormaalisti Päättynyt (kuollut) Säie valitaan suoritukseen Valmis Säie käynnistetään start komennolla Suorituksessa Aikakvantti loppunut, yield, interrupt IO suoritettu, uniaika loppunut, notify, notifyall IO pyyntö, sleep, wait Estynyt Uusi Säie luodaan HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.10/55

Raita: prioriteeteista MAX_PRIORITY p1 p2 p3 MIN_PRIORITY p4 HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.11/55

Säikeiden muodostus Säikeet ovat olioita! Kaksi tapaa muodostaa suorituskelpoinen säie. Tapa 1: Peritään luokasta Thread ja luodaan sen mukainen olio. Perittäessä kirjoitetaan säikeen toiminta run -metodiin. Tapa 2: Tehdään luokka X, joka toteuttaa rajapinnan Runnable ja sen run -metodin. Luodaan Thread-luokan olio antamalla parametriksi X:n olio. Säikeen tietosisällön muodostaminen erilaista. Vaikka tapa 1 perustuu perintään (extends), se ei ole erityisen rajoittavaa, koska... Moniperintä : tehdään sisäluokan mukainen Thread:n perivä luokka. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.12/55

Thread class PrimeThread extends Thread { private long minprime; PrimeThread(long minprime) { this.minprime = minprime; } } public void run() { // compute primes larger than minprime... } PrimeThread p = new PrimeThread(143); p.start(); HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.13/55

Runnable class PrimeRun implements Runnable { private long minprime; PrimeRun(long minprime) { this.minprime = minprime; } } public void run() { // compute primes larger than minprime... } PrimeRun p = new PrimeRun(143); new Thread(p).start(); HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.14/55

Luokka Thread 1/3 Ominaisuudet: prioriteetti, nimi ja säieryhmä, suorituskelpoinen kohde (itse, jos ei määrätty). Thread(ThreadGroup g, Runnable r, String n) Yleisin konstruktori. Ryhmä g, kohde r, nimi n ja sama prioriteetti kuin käynnistävällä säikeellä. setpriority, getpriority, setname, getname static Thread currentthread() Palauttaa säie-olion, josta metodia kutsutaan. void start() Käsketään aloittamaan kohdesäikeen suoritus (JVM kutsuu sen run :a). Luo toisen samanaikaisen käskyvirran. void run() Suoritettava koodi. Jos määritelty kohde, HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.15/55 suoritetaan sen run. Thread.run on tyhjä.

Luokka Thread 2/3 void interrupt() Keskeytetään kohdesäikeen suoritus. SecurityException: ei oikeutta. static boolean interrupted() Onko keskeytetty jonkun toimesta; kutsu nollaa interrupted-tilan. boolean isinterrupted() Onko kohdesäie keskeytetty? Sen tilaa ei muuteta. static void yield() Keskeyttää kutsuvan säikeen antaen suoritusvuoron seuraavalle. static void sleep(... ) Säie nukkuu ajan.... InterruptedException: toinen säie keskeyttää tämän. final boolean isalive() Onko säie vielä elossa? HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.16/55

Luokka Thread 3/3 final ThreadGroup getthreadgroup() Palauttaa säieryhmän. static int activecount() Montako aktiivista säiettä kutsuvan säikeen ryhmässä? static int enumerate(thread[] q) Kerää q:n kaikki tämän ryhmän säikeet, myös aliryhmistä. Palauttaa lukumäärän. final void join(... ) Odottaa... -ajan kohdesäikeen päättymistä. 0= ikuisesti. final void setdaemon(boolean b) Asettaa daemon-statuksen. Ennen start :a. final boolean isdaemon() Onko daemon-prosessi? HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.17/55

ThreadTester.java 1/2 public class ThreadTester { public static void main( String args[] ) { PrintThread säie1, säie2, säie3, säie4; säie1 = new PrintThread("Säie1"); säie2 = new PrintThread("Säie2"); säie3 = new PrintThread("Säie3"); säie4 = new PrintThread("Säie4"); System.err.println("\nSäikeiden käynnistys."); säie1.start(); säie2.start(); säie3.start(); säie4.start(); System.err.println( "Käynnistetty.\n" ); } // main } // ThreadTester HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.18/55

ThreadTester.java 2/2 class PrintThread extends Thread { private int sleeptime; public PrintThread(String name) { super(name); sleeptime = (int) (Math.random() 5000 ); System.err.println( "Nimi: " + getname() + "; Unessa: " + sleeptime ); } // PrintThread(String) public void run() { try { System.err.println(getName() + "menee nukkumaan" ); Thread.sleep(sleepTime); } catch (InterruptedException exception) { System.err.println( exception.tostring() ); } System.err.println(getName() + "heräsi" ); } // run } // PrintThread HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.19/55

ThreadTester: suoritus Nimi: Säie1; Unessa: 470 Nimi: Säie2; Unessa: 4677 Nimi: Säie3; Unessa: 1097 Nimi: Säie4; Unessa: 2419 Säikeiden käynnistys. Käynnistetty. Säie1 menee nukkumaan Säie2 menee nukkumaan Säie3 menee nukkumaan Säie4 menee nukkumaan Säie1 heräsi Säie3 heräsi Säie4 heräsi Säie2 heräsi HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.20/55

Raita: säikeiden tilat Suorituksen loppuminen normaalisti tai epänormaalisti Päättynyt (kuollut) Säie valitaan suoritukseen Valmis Säie käynnistetään start komennolla Suorituksessa Aikakvantti loppunut, yield, interrupt IO suoritettu, uniaika loppunut, notify, notifyall IO pyyntö, sleep, wait Estynyt Uusi Säie luodaan HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.21/55

Säikeiden tilasiirtymät 1/4 Säie on olio, jolla on havainnoitava tila. Samalla siihen liittyy käskyvirta. Tila päättynyt: run (tai vast) suoritettu loppuun. Ei voi enää uudelleen aktivoida. Tila suorituksessa: käytetään prosessoriaikaa (vain yksi tässä tilassa!). yield: luovutaan lopusta aikaviipaleesta. ( Seuraava valmis saa prosessorin.) sleep, join, wait: keskeytetään suoritus. Tehdään IO:ta Odotetaan sen päättymistä. Kohdataan lukko Odotetaan vapautumista. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.22/55

Säikeiden tilasiirtymät 2/4 Tila valmis: valmiina suoritukseen, odotetaan prosessoriaikaa. interrupt: joku keskeyttää säikeen: siirtyy valmis-tilaan. IO päättyi. Lukko vapautui (tai joku kertoi sen vapautuneen). Odotettiin säiettä, joka päättyi. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.23/55

Säikeiden tilasiirtymät 3/4 Tila estynyt: odotetaan jotakin ennen kuin voidaan tavoitella jatkamista. I/O:n loppuminen. sleep: suorituksessa estynyt wait: suorituksessa estynyt; Jokin toinen säie: nofity tai notifyall. Edellisiä sovelletaan johonkin olioon: lukitus & vapautus. synchronized: suorituksessa estynyt; jos olio lukittu; odottaa lukon vapautumista. interrupt: estynyt valmis. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.24/55

Säikeiden tilasiirtymät 4/4 join: odotetaan kunnes säikeen suoritus loppunut. wait lukko! Pitää saada ilmoitus (notify tai notifyall). wait: täytyy omata lukko nykyiseen olioon (se vapautetaan samalla). Jatkaminen edellyttää lukon saamista uudelleen! Tavallaan wait ilmaisee, että odotetaan jokin ehdon täyttymistä itse ehtoa ei kuitenkaan ilmaista mitenkään! HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.25/55

Counter.java class Counter implements Runnable { public Counter(int mi,int ma) { min = mi; max = ma; } public void run() { int m = getmax(); for ( int i = getmin(); i m; i++) { System.out.print(i + ); try { // Annetaan muillekin säikeille tilaisuus. Thread.sleep(100); } catch (InterruptedException e) { } } // for System.out.println(); } // run public int getmin() { return min; } public int getmax() { return max; } private final int min, max; // Range } // Counter HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.26/55

Coordinator.java 1/3 class Coordinator implements Runnable { private final int numcounters = 3; private final Thread[] counters = new Thread[numCounters]; protected Thread[] getcounters() { return counters; } public Coordinator() { initcounters(); } protected void initcounters() { Thread[] counters = getcounters(); for (int i = 0; i < counters.length; i++) { // Annetaan kullekin luotavalle säikeelle // oma toiminta-alueensa. final int min = 10 i+1, max = min+9; counters[i] = new Thread(new Counter(min,max)); } // for System.out.println("Säikeet luotu."); } // initcounters HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.27/55

Coordinator.java 2/3 public void run() { Thread mythread = Thread.currentThread(); int mypriority = mythread.getpriority(); Thread[] counters = getcounters(); for (int i = 0; i < counters.length; i++) { // Lasketaan säikeiden prioriteettia, jotta ne // eivät lähtisi käyntiin ennen aikojaan. counters[i].setpriority(mypriority-1); counters[i].start(); } // for System.out.println("Kaikki valmiina."); waitforcounterstofinish(mypriority); System.out.println("Kaikki säikeet ovat lopettaneet."); } // run HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.28/55

Coordinator.java 3/3 protected void waitforcounterstofinish(int mypriority) { // Lasketaan omaa prioriteettia, jotta alisäikeet // pääsevät suoritukseen. Thread mythread = Thread.currentThread(); mythread.setpriority(mypriority-1); do { try { Thread.sleep(500); } catch (InterruptedException e) { } } while (stillrunning()); } // waitforcounterstofinish protected boolean stillrunning() { // Loppuehto: Palauttaa arvon true, jos yksikin // säie on käynnissä. Thread[] counters = getcounters(); for (int i = 0; i < counters.length; i++) if (counters[i].isalive()) return true; return false; } // stillrunning } // Coordinator HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.29/55

Coordinator: suoritus Säikeet luotu. Kaikki valmiina. 1 11 21 2 12 22 3 13 23 4 14 24 5 15 25 6 16 26 7 17 27 8 18 28 9 19 29 10 20 30 Kaikki säikeet ovat lopettaneet. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.30/55

waitforcounterstofinnish (b) protected void waitforcounterstofinish(int mypriority) { Thread mythread = Thread.currentThread(); mythread.setpriority(mypriority-1); Thread[] counters = getcounters(); for (int i = 0; i < counters.length; i++) { // Anticipate being interrupted before the join is complete. boolean interrupted; do { try { interrupted = false; counters[i].join(); } catch (InterruptedException e) { interrupted = true; } } while(interrupted); } HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.31/55

Samanaikaisuuden ongelmista Halutaan jakaa tietoja, mutta tehdä niiden samanaikaiset muutokset kontrolloidusti. Miten välittää tietoa säikeeltä toiselle? Miten ajoittaa säikeiden suoritus? Esim. kuluttaja + tuottaja -tilanne. Miten taata, että säikeet saavat suoritusaikaa? Lukitusten avulla voidaan tehdä muutokset kontrolloidusti (olion eheys säilyy), mutta samanaikaiset lukot voivat johtaa lukkiumatilanteisiin. Valitettavasti yleistä lukkiumat välttävää ratkaisua ei ole. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.32/55

Javan ratkaisuista 1/2 Lukitus: olio voidaan lukita; siihen kiinnitetään monitori (mutex; mutually exclusive lock), joka sallii vain yhden säikeen operoivan oliolla kerrallaan. Varattu sana synchronized. Voidaan liittää metodeihin: kyseisiä metodeja saa käyttää vain yksi säie kerrallaan. Ei voida liittää luokka- tai instanssimuuttujiin. Voidaan liittää myös lausekkeeseen (olioon); sama vaikutus. Vaikka olioon on lukko, niin muut säikeet voivat käyttää olion ei-synkronoituja piireitä vapaasti. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.33/55

Javan ratkaisuista 2/2 Object.wait(... ): jäädään odottamaan jonkin asian/ehdon tapahtumista. Edellyttää lukkoa olioon; soveltaminen vapauttaa lukon. Object.notify(): ilmoitetaan, että asia tapahtunut. Edellyttää lukkoa olioon; antaa lukon jollekin sitä odottavista säikeistä. Object.notifyAll(): kaikki odottajat valmis -tilaan; joku saa lukon. Muut jäävät sitä odottamaan. Ongelma: kuka vapauttaa kaikki odottajat? Jonkun täytyy ensin ottaa lukko ja käyttää sitä sitten muiden vapauttamiseen. Vastuu!! wait & nofity:n idea on pyrkiä vähentämään lukkiumatilanteita. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.34/55

PrimeMaker.java class PrimeMaker extends Thread { private DataOutputStream out; public PrimeMaker(DataOutputStream o) { out = o; } public void run() { int newvalue = 1; try { while (newvalue < 10000) { newvalue = newvalue + 1; boolean isprime = true; for ( int i=2; i i newvalue; i++ ) if (newvalue % i == 0) { isprime = false; break; } if (isprime) { System.out.println("writing new prime " + newvalue); out.writeint(newvalue); } } // while out.close(); } catch (IOException e) { return; } } // run HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.35/55

FibMaker.java import java.io. ; class FibMaker extends Thread { private DataOutputStream out; public FibMaker(DataOutputStream o) { out = o; } public void run() { int n=0; int m=1; try { out.writeint(m); while (m < 10000) { int newvalue = n+m; n = m; m = newvalue; System.out.println("writing new Fibo " + newvalue); out.writeint(newvalue); } // while out.close(); } catch (IOException e) { return; } } // run } // FibMaker HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.36/55

PipeReader: idea putkesta PrimeMaker PipeReader FibMaker HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.37/55

PipeReader.java 1/2 import java.io. ; public class PipeReader { static public void main(string[] args) { PipeReader world = new PipeReader(System.out); } private PipeReader(PrintStream out) { DataInputStream fibs = makefibs(); DataInputStream primes = makeprimes(); try { int x = fibs.readint(), y = primes.readint(); while (x < 10000) { if (x == y) { out.println("integer " + x + "is both fib and prime"); x = fibs.readint(); y = primes.readint(); } else if (x < y) x = fibs.readint(); else y = primes.readint(); } // while } catch (IOException e) { System.exit(0); } } // PipeReader(PrintStream) HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.38/55

PipeReader.java 2/2 private DataInputStream makefibs() { try { PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(in); Thread fibthread = new FibMaker(new DataOutputStream(out)); fibthread.start(); return new DataInputStream(in); } catch (IOException e) { return null; } } // makefibs private DataInputStream makeprimes() { try { PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(in); Thread primethread = new PrimeMaker(new DataOutputStream(out)); primethread.start(); return new DataInputStream(in); } catch (IOException e) { return null; } } // makeprimes } // PipeReader HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.39/55

PipeReader: suorituksessa writing new Fibo 1 writing new Fibo 2 writing new Fibo 3 writing new Fibo 5... writing new Fibo 10946 writing new prime 2 writing new prime 3 writing new prime 5 writing new prime 7... writing new prime 643 Integer 2 is both fib and prime Integer 3 is both fib and prime Integer 5 is both fib and prime Integer 13 is both fib and prime Integer 89 is both fib and prime Integer 233 is both fib and prime writing new prime 647 HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.40/55

SharedData.java 1/3 public class SharedData { HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.41/55

SharedData.java 1/3 public class SharedData { private int sharefib = 0; private int shareprime = 0; private boolean writeablefib = true; private boolean writeableprime = true; HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.41/55

SharedData.java 1/3 public class SharedData { private int sharefib = 0; private int shareprime = 0; private boolean writeablefib = true; private boolean writeableprime = true; public synchronized void setfib(int newvalue) { } // setfib HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.41/55

SharedData.java 1/3 public class SharedData { private int sharefib = 0; private int shareprime = 0; private boolean writeablefib = true; private boolean writeableprime = true; public synchronized void setfib(int newvalue) { while (!writeablefib) { try { wait(); } catch (InterruptedException e) { e.printstacktrace(); } } // while } // setfib HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.41/55

SharedData.java 1/3 public class SharedData { private int sharefib = 0; private int shareprime = 0; private boolean writeablefib = true; private boolean writeableprime = true; public synchronized void setfib(int newvalue) { while (!writeablefib) { try { wait(); } catch (InterruptedException e) { e.printstacktrace(); } } // while System.out.println(Thread.currentThread().getName() + "setting sharefib to " + newvalue); sharefib = newvalue; writeablefib = false; notifyall(); } // setfib HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.41/55

SharedData.java 2/3 public synchronized void setprime(int newvalue) { while (!writeableprime) { try { wait(); } catch (InterruptedException e) { e.printstacktrace(); } } // while System.out.println(Thread.currentThread().getName() + "setting shareprime to " + newvalue); shareprime = newvalue; writeableprime = false; notifyall(); } // setprime HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.42/55

SharedData.java 2/3 public synchronized void setprime(int newvalue) { while (!writeableprime) { try { wait(); } catch (InterruptedException e) { e.printstacktrace(); } } // while System.out.println(Thread.currentThread().getName() + "setting shareprime to " + newvalue); shareprime = newvalue; writeableprime = false; notifyall(); } // setprime public synchronized int getprime() { } // getprime HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.42/55

SharedData.java 2/3 public synchronized void setprime(int newvalue) { while (!writeableprime) { try { wait(); } catch (InterruptedException e) { e.printstacktrace(); } } // while System.out.println(Thread.currentThread().getName() + "setting shareprime to " + newvalue); shareprime = newvalue; writeableprime = false; notifyall(); } // setprime public synchronized int getprime() { while (writeableprime) { try { wait(); } catch (InterruptedException e) { e.printstacktrace(); } } // while } // getprime HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.42/55

SharedData.java 2/3 public synchronized void setprime(int newvalue) { while (!writeableprime) { try { wait(); } catch (InterruptedException e) { e.printstacktrace(); } } // while System.out.println(Thread.currentThread().getName() + "setting shareprime to " + newvalue); shareprime = newvalue; writeableprime = false; notifyall(); } // setprime public synchronized int getprime() { while (writeableprime) { try { wait(); } catch (InterruptedException e) { e.printstacktrace(); } } // while writeableprime = true; System.out.println(Thread.currentThread().getName() + "retrieving shareprime value " + shareprime); notifyall(); return shareprime; } // getprime HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.42/55

SharedData.java 3/3 public synchronized int getfib() { while (writeablefib) { try { wait(); } catch (InterruptedException e) { e.printstacktrace(); } } // while writeablefib = true; System.out.println(Thread.currentThread().getName() + "retrieving sharefib value " + sharefib); notifyall(); return sharefib; } // getfib } // SharedData HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.43/55

FibThread.java public class FibThread extends Thread { } // FibThread HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.44/55

FibThread.java public class FibThread extends Thread { private SharedData handle; } // FibThread HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.44/55

FibThread.java public class FibThread extends Thread { private SharedData handle; public FibThread(SharedData sd) { super("fibthread"); handle = sd; } public void run() { } // run } // FibThread HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.44/55

FibThread.java public class FibThread extends Thread { private SharedData handle; public FibThread(SharedData sd) { super("fibthread"); handle = sd; } public void run() { int n=0, m=1; handle.setfib(m); } // run } // FibThread HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.44/55

FibThread.java public class FibThread extends Thread { private SharedData handle; public FibThread(SharedData sd) { super("fibthread"); handle = sd; } public void run() { int n=0, m=1; handle.setfib(m); while (m < 1000) { int newvalue = n+m; n = m; m = newvalue; handle.setfib(newvalue); } // while } // run } // FibThread HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.44/55

PrimeThread.java public class PrimeThread extends Thread { private SharedData handle; public PrimeThread(SharedData sd) { super("primethread"); handle = sd; } public void run() { int newvalue = 1; while (newvalue < 1000) { newvalue = newvalue + 1; boolean isprime = true; for ( int i=2; i i newvalue; i++ ) if (newvalue % i == 0) { isprime = false; break; } if (isprime) { handle.setprime(newvalue); } } // while } // run } // PrimeThread HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.45/55

ReaderThread.java public class ReaderThread extends Thread { private SharedData handle; ReaderThread(SharedData sd) { super("readerthread"); handle = sd; } public void run() { int x = handle.getfib(); int y = handle.getprime(); while (x < 1000) { if (x == y) { System.out.println("Integer " + x + "is both fib and prime"); x = handle.getfib(); y = handle.getprime(); } else if (x < y) x = handle.getfib(); else y = handle.getprime(); } // while } // run } // ReaderThread HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.46/55

SharedDataTest.java public class SharedDataTest { public static void main(string[] args) { SharedData sd = new SharedData(); Thread ft = new FibThread(sd); Thread pt = new PrimeThread(sd); Thread rt = new ReaderThread(sd); ft.start(); pt.start(); rt.start(); } // main } // SharedDataTest HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.47/55

SharedDataTest: suoritus FibThread setting sharefib to 1 ReaderThread retrieving sharefib value 1 PrimeThread setting shareprime to 2 FibThread setting sharefib to 1 ReaderThread retrieving shareprime value 2 ReaderThread retrieving sharefib value 1 PrimeThread setting shareprime to 3 FibThread setting sharefib to 2 ReaderThread retrieving sharefib value 2 Integer 2 is both fib and prime FibThread setting sharefib to 3 ReaderThread retrieving sharefib value 3 ReaderThread retrieving shareprime value 3 Integer 3 is both fib and prime PrimeThread setting shareprime to 5 FibThread setting sharefib to 5 ReaderThread retrieving sharefib value 5 ReaderThread retrieving shareprime value 5 Integer 5 is both fib and prime HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.48/55

Synkronoinnista lisää 1/2 synkronoitu lohko synchronized (lauseke) { /* Lauseita; lukitus on päällä */ } Lohkon suorituksen ajaksi hankitaan lukko lauseke :n arvona olevaan olioon. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.49/55

Synkronoinnista lisää 2/2 Synkronoinnin käytön vähentäminen: } public synchronized void method() { // Ei-kriittinen osa; // Kriittinen osa; // Ei-kriittinen osa; public void method() { // Ei-kriittinen osa; synchronized(this) { /* Kriittinen osa; */ } // Ei-kriittinen osa; HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.50/55

Prosessiryhmät Ideana on jakaa prosessit ryhmiksi, koska oletusarvoisesti saman ryhmän prosessit voivat vaikuttaa toistensa suoritukseen. Sama pätee aliryhmiin. Oletusarvoisesti säie kuuluu samaan ryhmään kuin sen luova säie. Turvallisuusmanageri kontrolloi asiaa. new ThreadGroup( Nimi ). Perustettavasta ryhmästä tulee perustajasäikeen ryhmän aliryhmä. JVM: voi suorittaa useita appletteja samanaikaisesti. Kunkin appletin säikeet sijoitetaan eri ryhmään. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.51/55

GroupCoordinator.java 1/2 class GroupCoordinator implements Runnable { public GroupCoordinator() { initcounters(); } protected void initcounters() { Thread[] counters = getcounters(); ThreadGroup group = getgroup(); for (int i = 0; i < counters.length; i++) { final int min = 10 i+1, max = min+9; counters[i] = new Thread(group, new Counter(min,max)); } System.out.println("All counters created."); } // initcounters public void run() { Thread[] counters = getcounters(); for ( int i = 0; i < counters.length; i++) counters[i].start(); System.out.println("All counters ready to run."); waitforcounterstofinish(); System.out.println("All the threads have finished."); HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.52/55 } // run

GroupCoordinator.java 2/2 protected void waitforcounterstofinish() { ThreadGroup group = getgroup(); do try { Thread.sleep(500); } catch (InterruptedException e) { } while (group.activecount() > 0); } // waitforcounterstofinish protected Thread[] getcounters() { return counters; } protected ThreadGroup getgroup() { return countergroup; } private final int numcounters = 3; private final Thread[] counters = new Thread[numCounters]; private final ThreadGroup countergroup = new ThreadGroup("counters"); } // GroupCoordinator HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.53/55

Demonit Demoni eli taustaprosessi. Prosessi voidaan määritellä tällaiseksi luonnin ja käynnistämisen välissä. Statusta ei voi muuttaa. Luonnin yhteydessä prosessit perivät isäntäprosessinsa statuksen. Idea on, että demonit palvelevat normaaleja user-säikeitä. Jos JVM:ssä ei muuta kuin demoneja, JVM:n suoritus lopetetaan ja demonit tapetaan. Esim. roskien kerääjä voisi olla demoni. HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.54/55

Yhteenveto Säikeet ovat olioita. JVM:n tapa käsitellä säikeitä. Luonti: Thread, Runnable. Tilat, siirtymien syyt. Tiedon jakaminen ja sen hallinta: lukitukset. synchronized. Prioriteetti. Säieryhmä. Demoni. Soveltaminen? GUIhin? Verkkosovellusten yhteydessä? Animointi? HOJ, c Ville Leppänen, IT, Turun yliopisto, 2012 p.55/55