Problem lösta genom multithreading
Multithreading uppfanns faktiskt för att uppnå två viktiga mål:-
Gör flera saker samtidigt.
I exemplet ovan utförde olika trådar (familjemedlemmar) flera handlingar parallellt: de diskade, gick till affären och packade saker.
Vi kan ge ett exempel som är närmare relaterat till programmering. Anta att du har ett program med ett användargränssnitt. När du klickar på 'Fortsätt' i programmet bör vissa beräkningar ske och användaren bör se följande skärm. Om dessa åtgärder utfördes sekventiellt, skulle programmet bara hänga sig efter att användaren klickat på knappen "Fortsätt". Användaren kommer att se skärmen med knappen "Fortsätt" tills programmet utför alla interna beräkningar och når den del där användargränssnittet uppdateras.
Jag antar att vi väntar ett par minuter!
Eller så kan vi omarbeta vårt program, eller, som programmerare säger, "parallellisera" det. Låt oss utföra våra beräkningar på en tråd och rita användargränssnittet på en annan. De flesta datorer har tillräckligt med resurser för att göra detta. Om vi tar den här vägen kommer programmet inte att frysa och användaren kommer att flytta smidigt mellan skärmarna utan att oroa sig för vad som händer inuti. Det ena stör inte det andra :)
-
Utför beräkningar snabbare.
Allt är mycket enklare här. Om vår processor har flera kärnor, och det har de flesta processorer idag, så kan flera kärnor hantera vår lista med uppgifter parallellt. Självklart, om vi behöver utföra 1000 uppgifter och var och en tar en sekund, kan en kärna avsluta listan på 1000 sekunder, två kärnor på 500 sekunder, tre på lite mer än 333 sekunder, etc.
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("I'm Thread! My name is " + getName());
}
}
För att skapa och köra trådar måste vi skapa en klass, få den att ärva java.lang . Trådklass och åsidosätt dess run() -metod. Det sista kravet är mycket viktigt. Det är i run() -metoden som vi definierar logiken för vår tråd att exekvera. Om vi nu skapar och kör en instans av MyFirstThread , kommer run () -metoden att visa en rad med ett namn: metoden getName() visar trådens "system"-namn, som tilldelas automatiskt. Men varför talar vi trevande? Låt oss skapa en och ta reda på det!
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
Konsolutgång: Jag är tråden! Jag heter Thread-2 I'm Thread! Jag heter Tråd-1 Jag är Tråd! Jag heter Tråd-0 Jag är Tråd! Jag heter Tråd-3 Jag är Tråd! Jag heter Thread-6 I'm Thread! Jag heter Thread-7 I'm Thread! Jag heter Thread-4 I'm Thread! Jag heter Thread-5 I'm Thread! Jag heter Thread-9 I'm Thread! Mitt namn är Thread-8 Låt oss skapa 10 trådar ( MyFirstThread -objekt, som ärver Thread ) och starta dem genom att anropa start() -metoden på varje objekt. Efter att ha anropat start() -metoden exekveras logiken i run()- metoden. Obs: trådnamnen är inte i ordning. Det är konstigt att de inte var sekventiellt:, Tråd-1 , Tråd-2 och så vidare? Som det händer är detta ett exempel på en tid då "sekventiellt" tänkande inte passar. Problemet är att vi bara har tillhandahållit kommandon för att skapa och köra 10 trådar. Trådschemaläggaren, en speciell operativsystemmekanism, bestämmer deras exekveringsordning. Dess exakta design och beslutsfattande strategi är ämnen för en djupgående diskussion som vi inte kommer att dyka in i just nu. Det viktigaste att komma ihåg är att programmeraren inte kan kontrollera exekveringsordningen för trådar. För att förstå allvaret i situationen, prova att köra main()-metoden i exemplet ovan ett par gånger till. Konsolutgång vid andra körningen: Jag är tråden! Jag heter Tråd-0 Jag är Tråd! Jag heter Thread-4 I'm Thread! Jag heter Tråd-3 Jag är Tråd! Jag heter Thread-2 I'm Thread! Jag heter Tråd-1 Jag är Tråd! Jag heter Thread-5 I'm Thread! Jag heter Thread-6 I'm Thread! Jag heter Thread-8 I'm Thread! Jag heter Thread-9 I'm Thread! Mitt namn är Thread-7 Console-utgång från den tredje körningen: I'm Thread! Jag heter Tråd-0 Jag är Tråd! Jag heter Tråd-3 Jag är Tråd! Jag heter Tråd-1 Jag är Tråd! Jag heter Thread-2 I'm Thread! Jag heter Thread-6 I'm Thread! Jag heter Thread-4 I'm Thread! Jag heter Thread-9 I'm Thread! Jag heter Thread-5 I'm Thread! Jag heter Thread-7 I'm Thread! Jag heter Thread-8
Problem skapade av multithreading
I vårt exempel med böcker såg du att multithreading löser mycket viktiga uppgifter och kan göra våra program snabbare. Ofta många gånger snabbare. Men multithreading anses vara ett svårt ämne. Faktum är att om det används felaktigt skapar det problem istället för att lösa dem. När jag säger "skapar problem", menar jag inte i någon abstrakt mening. Det finns två specifika problem som multithreading kan skapa: dödläge och tävlingsförhållanden. Deadlock är en situation där flera trådar väntar på resurser som hålls av varandra, och ingen av dem kan fortsätta att köras. Vi kommer att prata mer om det i efterföljande lektioner. Följande exempel kommer att räcka för nu:
- Tråd-1 slutar interagera med Objekt-1 och växlar till Objekt-2 så fort Tråd-2 slutar interagera med Objekt-2 och växlar till Objekt-1.
- Tråd-2 slutar interagera med Objekt-2 och växlar till Objekt-1 så fort Tråd-1 slutar interagera med Objekt-1 och växlar till 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();
}
}
}
Föreställ dig nu att programmet ansvarar för att driva en robot som lagar mat! Tråd-0 får ut ägg ur kylen. Tråd-1 sätter på spisen. Tråd-2 får en kastrull och sätter den på spisen. Tråd-3 tänder kaminen. Tråd-4 häller olja i pannan. Tråd-5 bryter äggen och häller dem i pannan. Tråd-6 slänger äggskalen i papperskorgen. Tråd-7 tar bort de kokta äggen från brännaren. Tråd-8 lägger de kokta äggen på en tallrik. Tråd-9 diskar. Titta på resultatet av vårt program: Tråd utförd: Tråd-0 Tråd utförd: Tråd-2 Tråd utförd Tråd-1 Tråd utförd: Tråd-4 Tråd utförd: Tråd-9 Tråd utförd: Tråd-5 Tråd utförd: Tråd-8 Tråd utförd: Tråd-7 Tråd utförd: Tråd-3 Är detta en komedi rutin? :) Och allt för att vårt programs arbete beror på exekveringsordningen för trådarna. Med tanke på den minsta överträdelse av den nödvändiga sekvensen förvandlas vårt kök till ett helvete, och en galen robot förstör allt runt omkring det. Detta är också ett vanligt problem i flertrådsprogrammering. Du kommer att höra om det mer än en gång. Som avslutning på den här lektionen skulle jag vilja rekommendera en bok om multithreading. 
GO TO FULL VERSION