The Codest
  • Par mums
  • Pakalpojumi
    • Programmatūras izstrāde
      • Frontend izveide
      • Backend izstrāde
    • Staff Augmentation
      • Frontend izstrādātāji
      • Backend izstrādātāji
      • Datu inženieri
      • Mākoņa inženieri
      • QA inženieri
      • Citi
    • Tā Konsultatīvais dienests
      • Audits un konsultācijas
  • Nozares
    • Fintech un banku darbība
    • E-commerce
    • Adtech
    • Healthtech
    • Ražošana
    • Loģistika
    • Automobiļu nozare
    • IOT
  • Vērtība par
    • CEO
    • CTO
    • Piegādes vadītājs
  • Mūsu komanda
  • Case Studies
  • Zināt, kā
    • Blogs
    • Tikšanās
    • Tiešsaistes semināri
    • Resursi
Karjera Sazinieties ar mums
  • Par mums
  • Pakalpojumi
    • Programmatūras izstrāde
      • Frontend izveide
      • Backend izstrāde
    • Staff Augmentation
      • Frontend izstrādātāji
      • Backend izstrādātāji
      • Datu inženieri
      • Mākoņa inženieri
      • QA inženieri
      • Citi
    • Tā Konsultatīvais dienests
      • Audits un konsultācijas
  • Vērtība par
    • CEO
    • CTO
    • Piegādes vadītājs
  • Mūsu komanda
  • Case Studies
  • Zināt, kā
    • Blogs
    • Tikšanās
    • Tiešsaistes semināri
    • Resursi
Karjera Sazinieties ar mums
Atpakaļ bultiņa ATGRIEZTIES ATPAKAĻ
2022-06-15
Programmatūras izstrāde

Vienlaicīgums Java 1. daļa - Ievads

The Codest

Rafal Sawicki

Java izstrādātājs

Izlasiet mūsu emuāru sērijas pirmo daļu, kas veltīta vienlaicīgai darbībai programmā Java. Turpmākajā rakstā mēs sīkāk aplūkosim atšķirības starp pavedieniem un procesiem, pavedienu baseiniem, izpildītājiem un daudz ko citu!

Kopumā tradicionālā programmēšanas pieeja ir secīga. Programmā viss notiek soli pa solim.
Taču patiesībā paralēli darbojas visa pasaule - tā ir spēja vienlaicīgi izpildīt vairāk nekā vienu uzdevumu.

Vītne pret procesu

Apspriest tādas progresīvas tēmas kā. vienlaicīgums Java vai daudzpavedienu režīmā, mums ir jāvienojas par kopīgām definīcijām, lai pārliecinātos, ka esam vienisprātis.

Sāksim ar pamatiem. Nesekvenciālajā pasaulē mums ir divu veidu vienlaicības reprezentanti: procesi un
pavedieni. Process ir izpildītas programmas gadījums. Parasti tas ir izolēts no citiem procesiem.
Operētājsistēma ir atbildīga par resursu piešķiršanu katram procesam. Turklāt tā darbojas kā diriģents, kas
plāno un kontrolē to izpildi.

Diegs ir sava veida process, bet zemākā līmenī, tāpēc to sauc arī par vieglo diegu. Vairāki pavedieni var darboties vienā
process. Šajā gadījumā programma darbojas kā plānošanas programma un pavedienu kontrolieris. Šādā veidā atsevišķas programmas, šķiet, veic
vairākus uzdevumus vienlaicīgi.

Pamatatšķirība starp pavedieniem un procesiem ir izolācijas līmenis. Procesam ir savs
resursus, savukārt pavediens koplieto dati ar citiem pavedieniem. Tā var šķist uz kļūdām tendēta pieeja, un tā patiešām ir. Attiecībā uz
tagad neiedziļināsimies šajā jautājumā, jo tas ir ārpus šī raksta darbības jomas.

Procesi, pavedieni - labi... Bet kas īsti ir vienlaicīgums? Vienlaicīga izpilde nozīmē, ka vienlaicīgi var izpildīt vairākus uzdevumus.
laiks. Tas nenozīmē, ka šiem uzdevumiem ir jāstrādā vienlaicīgi - tas ir paralēlisms. Concurrenc in Javay arī nav
ir nepieciešami vairāki procesori vai pat vairāki kodoli. To var panākt viena kodola vidē, izmantojot
konteksta pārslēgšana.

Ar vienlaicīgumu saistīts termins ir daudzpavedienu lietojums. Tā ir programmu iezīme, kas ļauj tām izpildīt vairākus uzdevumus vienlaicīgi. Ne visas programmas izmanto šo pieeju, bet tās, kas to dara, var saukt par daudzpavedienu programmām.

Mēs esam gandrīz gatavi doties ceļā, tikai vēl viena definīcija. Asinhronitāte nozīmē, ka programma veic nebloķējošas operācijas.
Tā uzsāk uzdevumu un pēc tam, gaidot atbildi, turpina veikt citas darbības. Kad tā saņem atbildi, tā var reaģēt uz to.

Viss šis džezs

Pēc noklusējuma katrs Java lietojumprogramma darbojas vienā procesā. Šajā procesā ir viens pavediens, kas saistīts ar galvenais() metode
pieteikumu. Tomēr, kā jau minēts, ir iespējams izmantot vairāku pavedienu mehānismus vienā sistēmā.
programma.

Runnable

Vītne ir Java klase, kurā notiek burvju darbība. Tas ir iepriekš minētā pavediena objekta attēlojums. Uz
izveidot savu pavedienu, varat paplašināt Vītne klase. Tomēr tā nav ieteicama pieeja. Diegi jāizmanto kā mehānisms, kas palaist uzdevumu. Uzdevumi ir kods ko vēlamies palaist vienlaicīgā režīmā. Tos varam definēt, izmantojot Runnable saskarne.

Bet pietiek ar teoriju, izmantosim kodu tur, kur ir mūsu mute.

Problēma

Pieņemsim, ka mums ir vairāki skaitļu masīvi. Katram masīvam mēs vēlamies uzzināt masīvā esošo skaitļu summu. Pieņemsim
izliekas, ka šādu masīvu ir daudz, un katrs no tiem ir salīdzinoši liels. Šādos apstākļos mēs vēlamies izmantot vienlaicīgumu un summēt katru masīvu kā atsevišķu uzdevumu.

int[] a1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] a2 = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
int[] a3 = {3, 4, 3, 4, 4, 3, 4, 2, 1, 3, 7};

Runnable task1 = () -> { {
    int sum = Arrays.stream(a1).sum();
    System.out.println("1. Summa ir: " + sum);
};

Runnable task2 = () -> {
    int sum = Arrays.stream(a2).sum();
    System.out.println("2. Summa ir: " + sum);
};

Runnable uzdevums3 = () -> {
    int sum = Arrays.stream(a3).sum();
    System.out.println("3. Summa ir: " + sum);
};

new Thread(task1).start();
new Thread(task2).start();
new Thread(task3).start();

Kā redzams iepriekš pievienotajā kodā. Runnable ir funkcionāla saskarne. Tā satur vienu abstraktu metodi palaist()
bez argumentiem. Portāls Runnable interfeiss jāimplementē jebkurai klasei, kuras eksemplāri ir paredzēti, lai būtu
izpilda pavediens.

Kad uzdevums ir definēts, varat izveidot pavedienu tā izpildei. To var izdarīt, izmantojot jauns pavediens() konstruktors, kas
aizņem Runnable kā argumentu.

Pēdējais solis ir sākt() jaunizveidots pavediens. API ir arī palaist() metodes Runnable un
Vītne. Tomēr tas nav veids, kā izmantot vienlaicīgumu Java. Katras no šīm metodēm tiešais izsaukums rada
izpildīt uzdevumu tajā pašā pavedienā, kurā galvenais() metode darbojas.

Vītņu pūli un izpildītāji

Ja ir daudz uzdevumu, nav laba ideja katram uzdevumam izveidot atsevišķu pavedienu. Izveidojot Vītne ir
smagsvara operācija, un ir daudz labāk atkārtoti izmantot esošos pavedienus, nevis radīt jaunus.

Ja programma rada daudz īslaicīgu pavedienu, labāk ir izmantot pavedienu pūlu. Vītņu fonds satur vairākus pavedienus.
gatavi darbam, bet pašlaik neaktīvi pavedieni. Sniedzot Runnable uz pūlu izraisa vienu no pavedieniem, kas izsauc
palaist() dotā metode Runnable. Pēc uzdevuma pabeigšanas pavediens joprojām pastāv un atrodas dīkstāves stāvoklī.

Labi, jūs saprotat - dodiet priekšroku pavedienu pūlam, nevis manuālai izveidei. Bet kā jūs varat izmantot pavedienu pūlus? Izmantojot Izpildītāji
klasē ir vairākas statiskas rūpnīcas metodes pavedienu pūlu konstruēšanai. Piemēram newCachedThredPool() izveido
pūlu, kurā pēc vajadzības tiek izveidoti jauni pavedieni un 60 sekundes tiek saglabāti dīkstāves pavedieni. Turpretī,
newFixedThreadPool() satur fiksētu pavedienu kopu, kurā bezdarbības pavedieni tiek glabāti neierobežotu laiku.

Apskatīsim, kā tas varētu darboties mūsu piemērā. Tagad pavedieni nav jāveido manuāli. Tā vietā mums ir jāizveido
ExecutorService kas nodrošina pavedienu kopfondu. Tad mēs varam tam piešķirt uzdevumus. Pēdējais solis ir slēgt pavedienu
pool, lai izvairītos no atmiņas noplūdes. Pārējais iepriekšējais kods paliek nemainīgs.

ExecutorService executor = Executors.newCachedThreadPool();

executor.submit(task1);
executor.submit(uzdevums2);
executor.submit(uzdevums3);

executor.shutdown();

Izsaucams

Runnable šķiet noderīgs veids, kā izveidot vienlaicīgus uzdevumus, taču tam ir viens būtisks trūkums. Tas nevar atdot nevienu
vērtība. Turklāt mēs nevaram noteikt, vai uzdevums ir vai nav pabeigts. Mēs arī nezinām, vai tas ir pabeigts.
parasti vai izņēmuma kārtā. Risinājums šīm slimībām ir Izsaucams.

Izsaucams ir līdzīgs Runnable tā ietver arī asinhronus uzdevumus. Galvenā atšķirība ir tā, ka tā spēj
atgriezt vērtību. Atgrieztā vērtība var būt jebkura (ne primitīvā) tipa, jo Izsaucams saskarne ir parametrizēts tips.
Izsaucams ir funkcionāla saskarne, kurai ir izsaukt() metode, kas var mest Izņēmums.

Tagad aplūkosim, kā mēs varam izmantot Izsaucams mūsu masīva problēmā.

int[] a1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] a2 = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
int[] a3 = {3, 4, 3, 4, 4, 3, 4, 2, 1, 3, 7};

Callable uzdevums1 = () -> Arrays.stream(a1).sum();
Callable task2 = () -> Arrays.stream(a2).sum();
Callable uzdevums3 = () -> Arrays.stream(a3).sum();

ExecutorService executor = Executors.newCachedThreadPool();
Future future1 = executor.submit(task1);
Future future2 = executor.submit(task2);
Future future3 = executor.submit(task3);

System.out.println("1. Summa ir: " + future1.get());
System.out.println("2. Summa ir: " + future2.get());
System.out.println("3. Summa ir: " + future3.get());

executor.shutdown();

Labi, mēs varam redzēt, kā Izsaucams tiek izveidots un pēc tam iesniegts ExecutorService. Bet kas, pie velna, ir Nākotne?
Nākotne darbojas kā tilts starp pavedieniem. Katra masīva summa tiek veidota atsevišķā pavedienā, un mums ir nepieciešams veids, kā
saņemt šos rezultātus atpakaļ uz galvenais().

Lai iegūtu rezultātu no Nākotne mums jāzvana iegūt() metode. Šeit var notikt viena no divām lietām. Pirmkārt,
aprēķina rezultāts, ko veic Izsaucams ir pieejams. Tad mēs to saņemam nekavējoties. Otrkārt, rezultāts nav
vēl nav gatavs. Tādā gadījumā iegūt() metode tiks bloķēta, līdz būs pieejams rezultāts.

ComputableFuture

Jautājums par Nākotne ir tas, ka tā darbojas saskaņā ar "push paradigmu". Izmantojot Nākotne jums ir jābūt kā priekšniekam, kurš
pastāvīgi jautā: "Vai tavs uzdevums ir izpildīts? Vai tas ir gatavs?", līdz tas sniedz rezultātu. Darbība pastāvīga spiediena apstākļos ir
dārgi. Daudz labāka pieeja būtu pasūtīt Nākotne ko darīt, kad tas ir gatavs savam uzdevumam. Diemžēl,
Nākotne to nevar izdarīt, bet ComputableFuture var.

ComputableFuture darbojas "pull paradigmā". Kad tas ir izpildījis savus uzdevumus, mēs varam tam norādīt, ko darīt ar rezultātu. Tas
ir asinhronas pieejas piemērs.

ComputableFuture lieliski darbojas ar Runnable bet ne ar Izsaucams. Tā vietā ir iespējams sniegt uzdevumu, lai
ComputableFuture veidā Piegādātājs.

Aplūkosim, kā iepriekš minētais attiecas uz mūsu problēmu.

int[] a1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] a2 = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
int[] a3 = {3, 4, 3, 4, 4, 3, 4, 2, 1, 3, 7};

CompletableFuture.supplyAsync(() -> Arrays.stream(a1).sum())
                .thenAccept(System.out::println);

CompletableFuture.supplyAsync(() -> Arrays.stream(a2).sum())
                .thenAccept(System.out::println);

CompletableFuture.supplyAsync(() -> Arrays.stream(a3).sum())
                .thenAccept(System.out::println);

Pirmais, kas jums pārsteidz, ir tas, cik daudz īsāks ir šis risinājums. Turklāt tas arī izskatās glīti un kārtīgi.

Uzdevums PabeidzamsBūtība var nodrošināt supplyAsync() metode, kas izmanto Piegādātājs vai RunAsync() ka
aizņem Runnable. Atgriezenisko zvanu - koda fragmentu, kas jāpalaiž pēc uzdevuma pabeigšanas - definē ar thenAccept()
metode.

Secinājumi

Java piedāvā daudz dažādu pieejas vienlaicīgai darbībai. Šajā rakstā mēs tikai nedaudz pieskārāmies šai tēmai.

Tomēr mēs aptvērām pamatus par Vītne, Runnable, Izsaucams, un CallableFuture kas izvirza labu punktu
tālākai tēmas izpētei.

Saistītie raksti

Programmatūras izstrāde

9 kļūdas, no kurām jāizvairās, programmējot Java valodā

No kādām kļūdām vajadzētu izvairīties, programmējot Java valodā? Šajā rakstā mēs atbildēsim uz šo jautājumu.

The Codest
Rafal Sawicki Java izstrādātājs
Uzņēmumu un mērogošanas risinājumi

Pareizais veids, kā atrast labākos Java izstrādātājus

Atrast ideālu Java izstrādātāju var būt grūts uzdevums. Tā kā tirgus pieprasījums pēc šādiem speciālistiem aug pārsteidzošā tempā, pieejamie talantu meklēšanas avoti dažkārt var šķist...

The Codest
Grzegorz Rozmus Java vienības vadītājs
Uzņēmumu un mērogošanas risinājumi

Kā Java var atbalstīt jūsu uzņēmumu?

Uzziniet, kā Java un Java virtuālā mašīna (JVM) nodrošina stabilu, mērogojamu biznesa programmatūru un kad ir lietderīgi izvēlēties Java.

Bartlomiej Kuczynski
Uzņēmumu un mērogošanas risinājumi

Diena programmētāja dzīvē uzņēmumā The Codest

Jums varētu rasties aizdomas, ka programmētāju darba grafiki viens no otra neatšķiras. Taču patiesībā tā nav taisnība! Katram jaunuzņēmumam, programmatūras uzņēmumam, pat korporācijai ir savs...

The Codest
Pawel Rybczynski Software Engineer

Abonējiet mūsu zināšanu bāzi un saņemiet jaunāko informāciju par IT nozares pieredzi.

    Par mums

    The Codest - starptautisks programmatūras izstrādes uzņēmums ar tehnoloģiju centriem Polijā.

    Apvienotā Karaliste - Galvenā mītne

    • 303B birojs, 182-184 High Street North E6 2JA
      Londona, Anglija

    Polija - Vietējie tehnoloģiju centri

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Krakova
    • Brain Embassy, Konstruktorska
      11, 02-673 Varšava, Polija

      The Codest

    • Sākums
    • Par mums
    • Pakalpojumi
    • Case Studies
    • Zināt, kā
    • Karjera
    • Vārdnīca

      Pakalpojumi

    • Tā Konsultatīvais dienests
    • Programmatūras izstrāde
    • Backend izstrāde
    • Frontend izveide
    • Staff Augmentation
    • Backend izstrādātāji
    • Mākoņa inženieri
    • Datu inženieri
    • Citi
    • QA inženieri

      Resursi

    • Fakti un mīti par sadarbību ar ārējo programmatūras izstrādes partneri
    • No ASV uz Eiropu: Kāpēc Amerikas jaunuzņēmumi nolemj pārcelties uz Eiropu?
    • Tehnoloģiju ārzonas attīstības centru salīdzinājums: Tech Offshore Eiropa (Polija), ASEAN (Filipīnas), Eirāzija (Turcija)
    • Kādi ir galvenie CTO un CIO izaicinājumi?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Autortiesības © 2026 The Codest. Visas tiesības aizsargātas.

    lvLatvian
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian es_ESSpanish nl_NLDutch etEstonian elGreek pt_PTPortuguese cs_CZCzech lt_LTLithuanian lvLatvian