Problemer løst ved multithreading
Multithreading blev faktisk opfundet for at nå to vigtige mål:-
Gør flere ting på samme tid.
I eksemplet ovenfor udførte forskellige tråde (familiemedlemmer) flere handlinger parallelt: de vaskede op, gik i butikken og pakkede ting.
Vi kan tilbyde et eksempel, der er tættere relateret til programmering. Antag, at du har et program med en brugergrænseflade. Når du klikker på 'Fortsæt' i programmet, skulle der ske nogle beregninger, og brugeren skulle se følgende skærmbillede. Hvis disse handlinger blev udført sekventielt, ville programmet bare hænge, efter at brugeren har klikket på knappen 'Fortsæt'. Brugeren vil se skærmen med knappen 'Fortsæt', indtil programmet udfører alle interne beregninger og når den del, hvor brugergrænsefladen er opdateret.
Nå, jeg tror, vi venter et par minutter!
Eller vi kunne omarbejde vores program, eller, som programmører siger, 'parallelle' det. Lad os udføre vores beregninger på en tråd og tegne brugergrænsefladen på en anden. De fleste computere har ressourcer nok til at gøre dette. Hvis vi tager denne rute, så fryser programmet ikke fast, og brugeren vil bevæge sig jævnt mellem skærme uden at bekymre sig om, hvad der sker indeni. Det ene forstyrrer ikke det andet :)
-
Udfør beregninger hurtigere.
Alt er meget enklere her. Hvis vores processor har flere kerner, og det har de fleste processorer i dag, så kan flere kerner håndtere vores liste over opgaver parallelt. Det er klart, at hvis vi skal udføre 1000 opgaver og hver tager et sekund, kan en kerne afslutte listen på 1000 sekunder, to kerner på 500 sekunder, tre på lidt mere end 333 sekunder osv.
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("I'm Thread! My name is " + getName());
}
}
For at oprette og køre tråde skal vi oprette en klasse, få den til at arve java.lang . Trådklasse , og tilsidesæt dens run()- metode. Det sidste krav er meget vigtigt. Det er i run() -metoden, vi definerer logikken for, at vores tråd skal udføres. Hvis vi nu opretter og kører en instans af MyFirstThread , vil run() -metoden vise en linje med et navn: getName()- metoden viser trådens 'system'-navn, som tildeles automatisk. Men hvorfor taler vi foreløbigt? Lad os oprette en og finde ud af det!
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
Konsoludgang: Jeg er tråd! Mit navn er Tråd-2 Jeg er Tråd! Mit navn er Tråd-1 Jeg er Tråd! Mit navn er Tråd-0 Jeg er Tråd! Mit navn er tråd-3 jeg er tråd! Mit navn er Thread-6 I'm Thread! Mit navn er Thread-7 I'm Thread! Mit navn er Thread-4 I'm Thread! Mit navn er Tråd-5 Jeg er Tråd! Mit navn er Thread-9 I'm Thread! Mit navn er Thread-8 Lad os oprette 10 tråde ( MyFirstThread- objekter, som arver Thread ) og starte dem ved at kalde start()- metoden på hvert objekt. Efter at have kaldt start()- metoden, udføres logikken i run() -metoden. Bemærk: trådnavnene er ikke i orden. Det er mærkeligt, at de ikke var sekventielt:, Tråd-1 , Tråd-2 og så videre? Som det sker, er dette et eksempel på en tid, hvor 'sekventiel' tænkning ikke passer. Problemet er, at vi kun har givet kommandoer til at oprette og køre 10 tråde. Trådplanlæggeren, en speciel operativsystemmekanisme, bestemmer deres udførelsesrækkefølge. Dets præcise design og beslutningsstrategi er emner for en dyb diskussion, som vi ikke vil dykke ned i lige nu. Det vigtigste at huske er, at programmøren ikke kan kontrollere udførelsesrækkefølgen af tråde. For at forstå alvoren af situationen, prøv at køre main()-metoden i eksemplet ovenfor et par gange mere. Konsoludgang ved anden kørsel: Jeg er tråd! Mit navn er Tråd-0 Jeg er Tråd! Mit navn er Thread-4 I'm Thread! Mit navn er tråd-3 jeg er tråd! Mit navn er Tråd-2 Jeg er Tråd! Mit navn er Tråd-1 Jeg er Tråd! Mit navn er Tråd-5 Jeg er Tråd! Mit navn er Thread-6 I'm Thread! Mit navn er Thread-8 I'm Thread! Mit navn er Thread-9 I'm Thread! Mit navn er Thread-7 Console output fra tredje kørsel: I'm Thread! Mit navn er Tråd-0 Jeg er Tråd! Mit navn er tråd-3 jeg er tråd! Mit navn er Tråd-1 Jeg er Tråd! Mit navn er Tråd-2 Jeg er Tråd! Mit navn er Thread-6 I'm Thread! Mit navn er Thread-4 I'm Thread! Mit navn er Thread-9 I'm Thread! Mit navn er Tråd-5 Jeg er Tråd! Mit navn er Thread-7 I'm Thread! Mit navn er tråd-8
Problemer skabt af multithreading
I vores eksempel med bøger så du, at multithreading løser meget vigtige opgaver og kan gøre vores programmer hurtigere. Ofte mange gange hurtigere. Men multithreading anses for at være et vanskeligt emne. Faktisk, hvis det bruges forkert, skaber det problemer i stedet for at løse dem. Når jeg siger 'skaber problemer', mener jeg ikke i en eller anden abstrakt forstand. Der er to specifikke problemer, som multithreading kan skabe: dødvande og racerforhold. Deadlock er en situation, hvor flere tråde venter på ressourcer, der holdes af hinanden, og ingen af dem kan fortsætte med at køre. Vi vil tale mere om det i de efterfølgende lektioner. Følgende eksempel vil være tilstrækkeligt for nu:
- Tråd-1 stopper med at interagere med Objekt-1 og skifter til Objekt-2, så snart Tråd-2 stopper med at interagere med Objekt-2 og skifter til Objekt-1.
- Tråd-2 stopper med at interagere med Objekt-2 og skifter til Objekt-1, så snart Tråd-1 stopper med at interagere med Objekt-1 og skifter til Objekt-2.
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("Thread executed: " + getName());
}
}
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
Forestil dig nu, at programmet er ansvarligt for at køre en robot, der laver mad! Tråd-0 får æg ud af køleskabet. Tråd-1 tænder for komfuret. Tråd-2 får en pande og sætter den på komfuret. Tråd-3 tænder ovnen. Tråd-4 hælder olie i gryden. Tråd-5 knækker æggene og hælder dem i gryden. Tråd-6 smider æggeskallerne i skraldespanden. Tråd-7 fjerner de kogte æg fra brænderen. Tråd-8 lægger de kogte æg på en tallerken. Tråd-9 vasker op. Se på resultaterne af vores program: Tråd udført: Tråd-0 Tråd udført: Tråd-2 Tråd udført Tråd-1 Tråd udført: Tråd-4 Tråd udført: Tråd-9 Tråd udført: Tråd-5 Tråd udført: Tråd-8 Tråd udført: Tråd-7 Tråd udført: Tråd-3 Er dette en komedie rutine? :) Og alt sammen fordi vores programs arbejde afhænger af udførelsesrækkefølgen af trådene. Givet den mindste overtrædelse af den krævede sekvens, bliver vores køkken til et helvede, og en sindssyg robot ødelægger alt omkring det. Dette er også et almindeligt problem i flertrådsprogrammering. Du vil høre om det mere end én gang. Som afslutning på denne lektion vil jeg gerne anbefale en bog om multithreading. 
GO TO FULL VERSION