P|||Q
812315A Ohjelmiston
rakentaminen.
Asynkronisuus
Ari Vesanen
ari.vesanen (at) oulu.fi
P|||Q
Yleistä moduulista
Tällä kertaa sisältää Java-kielistä monisäieohjelmointia
Suoritustapa: Neljästä ohjelmointitehtävästä valitaan
kaksi, joihin laaditaan ratkaisut
Arvostellaan 1-5, loppuarvosana keskiarvo
mahdollisesti ylöspäin pyöristettynä
Suositellaan tekemään Javalla, C++ mahdollinen,
muista kielistä sovittava erikseen
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
2
P|||Q
Moduulin aikataulu
Aloitusseminaari 16.6. klo 10-16
Lyhyt johdanto rinnakkaisuuteen ja Java-kielen
monisäieohjelmointiin
Rinnakkaisuuden piirteitä ja ohjelmointitehtäviä
Suoritettavien tehtävien läpikäynti
17.6. – 4.8. Kiivasta ohjelmointia ja tehtävien palautus
viimeistään 4.8
Jokainen palauttaa omat ratkaisut
Lopetusseminaari 5.8. klo 10 - 16
Käydään läpi ratkaisut ja vertaillaan niitä toisiinsa
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
3
P|||Q
Moduulin sisältö
I. Johdanto rinnakkaisuuteen
II. Javan rinnakkaisuuden perustoteutus
III. Rinnakkaisen ohjelmoinnin malleja
IV. Eloisuusongelmista
V. Edistyneempi Javan rinnakkaisuus
VI. Tehtävät
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
4
P|||Q
Kirjallisuutta
Goetz, B. et al.:
Java Concurrency in Practice, Addison-Wesley 2010
González, J.:
Java 7 Concurrency Cookbook. Packt Publishing 2012.
Hartley, S.:
Concurrent Programming, The Java Programming
Language, Oxford University Press Inc. 1998
Lea, D.:
Concurrent Programming in Java, design Principles
and Patterns Second Edition, Addison-Wesley 2000
Kaksi viimeistä ennen Java 5.0:aa
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
5
P|||Q
WWW-lähteitä
Javan API-dokumentaatio:
https://docs.oracle.com/javase/8/docs/api/
Oraclen Java-tutoriaali
http://docs.oracle.com/javase/tutorial/essential/concurrency
Muita Java-tutoriaaleja
http://www.tutorialspoint.com/java/java_multithreading.htm
http://tutorials.jenkov.com/java-concurrency/index.html
Aalto-yliopiston kurssi
https://noppa.aalto.fi/noppa/kurssi/t-106.5600/luennot
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
6
P|||Q
I Johdanto rinnakkaisuuteen
Peräkkäinen
Käskyt suoritetaan
peräkkäin
Yksikäsitteinen
suorituspolku
Deterministinen
sama syöte,
sama tulos aina
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
vs.
Rinnakkainen
Toimintoja
suoritetaan
rinnakkain
Ei selvää
suorituspolkua
Epädeterministinen
tulos voi riippua
suoritusjärjestyksestä
812315 Ohjelmiston rakentaminen, Asynkronisuus
7
P|||Q
I.1 Prosessit ja säikeet
Prosessi
Tapa ajaa useita ohjelmia rinnakkain yhdessä
prosessorissa
Oma muistialue
Kommunikointi esim. putkilla tai socketeilla
Säie
Prosessia kevyempi
Prosessi voidaan jakaa säikeisiin
Säikeellä oma ohjelmalaskuri ja pino
Säikeet jakavat prosessin muistialueen ja resurssit
Tässä moduulissa monisäieohjelmointia
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
8
P|||Q
I.2 Rinnakkaisen ohjelman oikeellisuuskriteerit
Turvallisuus (safety)
Oliot ja muuttujat pysyvät kunnossa
Eloisuus (liveness)
Kaikki aiotut operaatiot suoritetaan joskus
Turvallisuus:
Ei-atomaarinen operaatio voi epäonnistua jos kaksi
säiettä toimii yhtä aikaa -> Metodi voi toimia väärin
jos sitä kutsutaan kahdesta säikeestä
Säieturvallinen (thread safe): toimii oikein millä tahansa
kutsujärjestyksellä
Resurssin käsitteleminen kahdesta säikeestä
samanaikaisesti = kilpailutilanne (race condition)
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
9
P|||Q
I.2 Rinnakkaisen ohjelman oikeellisuuskriteerit
Eloisuus:
Aiotut operaatiot suoritetaan – ei aikarajaa
Reaaliaikainen ohjelmointi – asetetaan aikarajoja
Turvallisuus ja eloisuus jossain määrin vastakkaisia
Ongelmatilanteisiin varauduttava suunnitteluvaiheessa
Ohjelman debuggaus erittäin vaikeaa (lokitiedoston
kirjoitus usein auttaa)
Ohjelman täydellinen testaus mahdotonta
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
10
P|||Q
II Javan rinnakkaisuuden perustoteutus
Java alkujaan suunniteltu tukemaan rinnakkaisuutta
Olio-ohjelmoinnin ja Javan perusteet oletetaan
tunnetuksi
Javan virtuaalikone (JVM) suorittaa Java-ohjelman
huolehtii myös rinnakkaisuudesta
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
11
P|||Q
II.1. Javan säikeet
Käyttäjäsäikeet (user threads)
varsinaiset säikeet
Taustasäikeet (daemon threads)
toimivat taustalla
Ohjelma loppuu, kun
sen kaikki käyttäjäsäikeet päättyvät tai
kutsutaan Runtime luokan exit()-metodia (koodissa
System.exit(0);)
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
12
P|||Q
II.1. Javan säikeet. Säikeen tilat
Uusi (NEW)
Säie on luotu, ei voi vielä toimia
Ajettava (RUNNABLE)
Säie voi toimia, kun saa suoritusaikaa
Estetty (BLOCKED)
Toiminta on estetty, koska odottaa lukon vapautumista
Odottaa (WAITING)
Säie odottaa toisen säikeen operaatiota
Odottaa ajastetusti (TIMED_WAITING)
Kuten yllä tai kun annettu aika on kulunut
Lopetettu, kuollut (TERMINATED)
Säikeen suoritus on loppunut
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
13
P|||Q
II.1. Javan säikeet. Säikeen luominen
1.
2.
3.
Kirjoita luokka, joka perii Thread-luokan
run()-metodi uudelleenmääriteltävä
TAI
Kirjoita luokka joka toteuttaa Runnable –rajapinnan
toteutettava run()-metodi
Säikeen suorittaminen:
Luo uusi Thread-olio
Konfiguroi (ei pakollinen)
Anna prioriteetti ja nimi
Käynnistä kutsumalla start()-metodia
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
14
P|||Q
II.1. Javan säikeet. Säikeen luominen (2)
HUOM1: Käynnistys kutsumalla startia, toiminnallisuus
runissa!
HUOM2: Säie päättyy, kun run loppuu
Testaa ohjelmia
Basicthreads.java
BasicRunnable.java
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
15
P|||Q
II.1. Javan säikeet. Säikeen lopettaminen
Säie päättyy kun run loppuu
Suositeltavin tapa säikeen keskeyttämiseen: interrupt
asettaa säikeen keskeytystilaan, ei lopeta suoritusta
tutki onko keskeytetty (metodi isInterrupted())
myös interrupted() - nollaa keskytystilan
Nukkuvan tai odottavan säikeen keskeyttäminen
aiheuttaa poikkeuksen InterruptedException
säie ei ajossa -> ei voi suoraan keskeyttää
ko. poikkeus on aina käsiteltävä kun tehdään wait tai
sleep
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
16
P|||Q
II.1. Javan säikeet. Säikeen lopettaminen
//Määritellään säieluokka
class Interruptible extends Thread{
public void run(){
while(!this.isInterrupted()){ // Tee jotain}
// Lopputoimenpiteet
}
}
//Pääohjelmassa koodi:
Interruptible irThread = new Interruptible();
irThread.start();
// Toimenpiteitä pääohjelmassa
// Lopetetaan irThread
irThread.interrupt();
Tehtävä ThreadInterrupt.java
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
17
P|||Q
II.2. Javan säikeiden synkronointi
1.
2.
Oikean toiminnan varmistamiseksi kahdenlaista
synkronointia
Kilpailun synkronointi
Tarvitaan kun resurssia käytetään monesta säikeestä
Yhteistoiminnan synkronointi
Tarvitaan kun säikeen toiminta riippuu toisen säikeen
toiminnasta
Javan perusmekanismi monitori = olio, jolla on lukko ja
odotusjoukko
Mikä tahansa Javan olio voi olla monitori
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
18
P|||Q
II.2.1 Javan monitorin toiminta
SP. JOUKKO
SÄIE 5
SÄIE 6
Odotusjoukko (wait
set) = ne säikeet
jotka odottavat
ilmoitusta (notify())
kutsuttuaan wait() –
metodia
METODI1
SÄIE 1
METODI2 Sisäänpääsyjoukko
LOHKO1
SÄIE 3
SÄIE 2
SÄIE 4
(entry set) =
säikeet, jotka
odottavat pääsyä
monitoriin
ensimmäistä kertaa
ODOTUSJOUKKO
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
19
P|||Q
II.2.2 Kilpailun synkronointi
Lukko otetaan haltuun kutsumalla synchronizedavainsanalla merkittyä metodia (tai koodilohkoa)
olion kaikkien synkronoitujen metodien ja lohkojen
suorittaminen estyy kunnes säie luopuu lukosta
Lukosta luopuminen:
Synkronoitu metodi/lohko loppuu
Säie siirtyy odotustilaan
HUOM! Thread.sleep(); ei aiheuta lukosta luopumista.
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
20
P|||Q
II.2.2 Kilpailun synkronointi (2)
ESIM: Seuraavat yhtäpitävät:
synchronized void f(){
// Metodin runko
}
void f(){
synchronized(this){
// Metodin runko
}
}
Tehtävä: Poista kilpailutilanne ohjelmista
RaceCondition.java ja UnsafeTicketOffice.java
Optimoi synkronointi jälkimmäisessä
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
21
P|||Q
II.2.3 Yhteistoiminnan synkronointi
Säikeessä voidaan odottaa toisen säikeen päättymistä
kutsumalla sen join()-metodia
Monitorin odotusjoukkoon voidaan vaikuttaa metodeilla
wait(): asettaa kutsuvan säikeen odotustilaan
notify(): vapauttaa yhden odottavan säikeen
notifyAll(): vapauttaa kaikki odottavat säikeet
Kaikkien em. metodien kutsumiseksi on oltava hallussa
monitorin lukko
Vapautetut säikeet kilpailevat normaaliin tapaan
monitorin lukosta
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
22
P|||Q
II.2.3 Yhteistoiminnan synkronointi (2)
Jos odottava säie keskeytetään, syntyy
InterruptedException
Käsiteltävä, jos kutsutaan wait()-metodia
Tehtävä: Ohjelmassa PingPongEx.java kaksi säiettä
kutsuu luokan PingPongController metodeja, jotka
tulostavat sanat ”PING” ja ”PONG”
Synkronoi luokka PingPongController niin, että sanat
tulostetaan aina vuorotellen. Metodeissa esiintyviä
sleep-aikoja ei saa muuttaa
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
23
P|||Q
III Rinnakkaisen ohjelmoinnin malleja
III.1 Tuottaja-kuluttajamalli
Soveltuu moneen rinnakkaisen ohjelmoinnin ongelmaan
Kahdentyyppisiä säikeitä (tai prosesseja):
Tuottajat
Luovat uusia olioita (dataa)
Kuluttaja
Käsittelevät tuottajien luomia olioita
Olioiden varastona voidaan käyttää esim. synkronoitua
syklistä puskuria:
Huolehdittava, että vain yksi säie käsittelee puskuria
Huolehdittava että täyteen puskuriin ei kirjoiteta
Huolehdittava että tyhjästä puskurista ei lueta
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
24
P|||Q
III.2 Lukija-kirjoittajamalli
Alunperin mallinsi tietokannan toimintaa
Yleishyödyllinen rinnakkaisessa ohjelmoinnissa
Voidaan käyttää säätelemään pääsyä monenlaisiin
resursseihin
Kahdenlaisia säikeitä: lukijasäikeet ja kirjoittajasäikeet
resurssia saa lukea moni säie yhtä aikaa
resurssia voi päivittää vain yksi (kirjoittaja)säie
resurssia ei saa lukea jos kirjoitetaan
Abstrakti luokka ReadAndWRite mallintaa toimintaa,
operaatiot readOperation() ja writeOperation()
määriteltävä perivässä luokassa
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
25
P|||Q
IV Eloisuusongelmat
Lukkiutuminen (deadlock)
Yleinen syy säikeiden jumittumiseen
Säikeet odottavat ristiin toistensa lukitsemien
resurssien vapautumista
Uloslukkiutuminen
Koodi voi sisältää sisäkkäisiä olioita joilla
synkronoituja metodeja -> Säie voi lukita itsensä ulos
Menetetty signaali
Säie odottaa signaalia, joka on tuotettu ennen kuin
säie alkoi odottaa
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
26
P|||Q
V Javan edistyneempi rinnakkaisuuden hallinta
Javan versioon 5.0 lisätukea rinnakkaisuuden hallintaan
java.util.concurrent
java.util.concurrent.locks
java.util.concurrent.atomic
Em. Pakkaukset sisältävät
Erilaisia synkronointiprimitiivejä,
Rinnakkaisessa ohjelmoinnissa käyttökelpoisia
kokoelmia,
Säieturvallisia muuttujatyyppejä
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
27
P|||Q
V.1 Semaforit
Semafori: kokonaislukumuuttuja, jonka arvo on lupien
lukumäärä
Säie pyytää lupaa semaforilta:
Jos arvo suurempi kuin nolla, säie saa luvan ja arvoa
vähennetään
Jos arvo nolla, säie jää odottamaan, kunnes lupien
määrä kasvaa
Kun säie luopuu luvasta, semaforin arvoa kasvatetaan
Voidaan käyttää poissulkevuuteen tai synkronoituna
laskurina
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
28
P|||Q
V.1 Semaforit (2)
Javassa semafori luokka Semaphore, pakkauksessa
java.util.concurrent
Käyttö:
// Luodaan semafori, jolla alussa yksi lupa
Semaphore sema = new Semaphore(1);
// Luvan pyytäminen
sema.acquire();
// Luvan vapauttaminen
sema.release();
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
29
P|||Q
V.2 Lukot ja ehtomuuttujat
Pakkauksessa java.util.concurrent.locks rajapinta Lock
Erilaisia implementointeja -> perussynkronointia
monipuolisempi toteutus
Lukkoihin voidaan liittää Condition-rajapinnan
toteuttavia olioita vastaamaan ehtomuuttujia
Käyttöidiomi kilpailun synkronoinnille
Lock lukko = ...; // Sopiva lukko-olio
lukko.lock();
try { // Käytä lukon suojaamaa resurssia
}
finally {
lukko.unlock(); // Varma vapauttaminen
}
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
30
P|||Q
V.2 Lukot ja ehtomuuttujat (2)
Luokan ReentrantLock olio Javan monitorin yleistys
Olioon voi liittyä useita ehtomuuttujia (Condition),
luodaan luokan metodilla newCondition()
Condition-olion odotusmetodi await() ja
ilmoitusmetodit signal() sekä signalAll()
Vastaavat Object-luokan metodeja wait(), notify() sekä
notifyAll()
Katso esimerkkiohjelmista CircularBufferWithLocks.java
Tehtäviä: Poista ohjelmista RaceConditionRunnable.java
ja UnsafeTicketOffice.java kilpailutilanne lukkoja
käyttämällä. Muuta aiemmin tehty PingPong-ohjelma
käyttämään lukkoja.
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
31
P|||Q
V.3 Suorittajat ja säievarastot
Javan pakkaukseen java.util.concurrent sisältyy rajapinta
Executor, jonka avulla voidaan eristää tehtävän välitys ja
sen suoritusmekanismi toisistaan.
Metodi void execute(Runnable r)
Toteuttamalla rajapinta saadaan erilaisia suorittajia
Luokissa voidaan käyttää Executor-oliota ja sitoa se
vasta myöhemmin tietyntyyppiseen suorittajaan, esim
class SimpleExecutor implements Executor{
public void execute(Runnable r){
new Thread(r).start();
}
}
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
32
P|||Q
V.3.1 Säievarastot
Kiinteä määrä säikeitä, joille annetaan tehtäviä
suoritettavaksi
Vähentää tarvittavien säikeiden määrää, jos tehtävien
ei tarvitse olla yhtä aikaa ajossa
Javan luokka ThreadPoolExecutor
Olio saadaan kutsumalla Executors-luokan staattista
metodia newFixedThreadPool(int poolSize)
Tehtävä käynnistetään luokan metodilla execute ->
pääsee suoritukseen kun varaston säie vapautuu
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
33
P|||Q
V.3.1 Säievarastot (2)
Javan luokka ThreadPoolExecutor jatkuu
Luokan metodi shutdown() -> tehtävät ajetaan
loppuun, uusia ei oteta
Luokan metodi awaitForTermination() odottaa kunnes
kaikki tehtävät suoritettu
Ks. esimerkit NQueensWithPool.java ja
NQueensWithPoolLatch.java
Tehtävä: Jälkimmäisessä CountDownLatch odottaa
tehtävien valmistumista. Korvaa se semaforilla.
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
34
P|||Q
VI Tehtävät
1.
2.
3.
4.
Jokainen palauttaa oman ratkaisun
Seuraavista neljästä tehtävästä valitaan kaksi
Kuvaukset erillisessä dokumentissä
Boolimaljasimulaatio
Kanjonia ylittävät turistit
Huvipuiston vuoristorata
Neljä samaa numeroa -peli
Ari Vesanen, Tietojenkäsitttelytieteiden laitos
812315 Ohjelmiston rakentaminen, Asynkronisuus
35
© Copyright 2025