CodeGym /Java-blogg /Tilfeldig /Bedre sammen: Java og Thread-klassen. Del I — Tråder om h...
John Squirrels
Nivå
San Francisco

Bedre sammen: Java og Thread-klassen. Del I — Tråder om henrettelse

Publisert i gruppen

Introduksjon

Multithreading ble bygget inn i Java helt fra begynnelsen. Så, la oss kort se på dette som kalles multithreading. Bedre sammen: Java og Thread-klassen.  Del I - Tråder om henrettelse - 1Vi tar den offisielle leksjonen fra Oracle som et referansepunkt: " Leksjon: "Hello World!"-applikasjonen ". Vi vil endre koden til Hello World-programmet vårt som følger:

class HelloWorldApp {
    public static void main(String[] args) {
        System.out.println("Hello, " + args[0]);
    }
}
argser en rekke inndataparametere som sendes når programmet startes. Lagre denne koden i en fil med et navn som samsvarer med klassenavnet og har filtypen .java. Kompiler den ved å bruke javac- verktøyet: javac HelloWorldApp.java. Deretter kjører vi koden vår med en eller annen parameter, for eksempel "Roger": java HelloWorldApp Roger Bedre sammen: Java og Thread-klassen.  Del I - Tråder om henrettelse - 2Koden vår har for øyeblikket en alvorlig feil. Hvis du ikke sender noen argumenter (dvs. kjører bare "java HelloWorldApp"), får vi en feilmelding:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
        at HelloWorldApp.main(HelloWorldApp.java:3)
Et unntak (dvs. en feil) oppstod i tråden med navnet "main". Så, Java har tråder? Det er her reisen vår begynner.

Java og tråder

For å forstå hva en tråd er, må du forstå hvordan et Java-program starter. La oss endre koden vår som følger:

class HelloWorldApp {
    public static void main(String[] args) {
		while (true) { 
			// Do nothing
		}
	}
}
La oss nå kompilere den igjen med javac. For enkelhets skyld kjører vi Java-koden vår i et eget vindu. På Windows kan dette gjøres slik: start java HelloWorldApp. Nå skal vi bruke jps- verktøyet for å se hvilken informasjon Java kan fortelle oss: Bedre sammen: Java og Thread-klassen.  Del I - Tråder om henrettelse - 3Det første tallet er PID eller prosess-ID. Hva er en prosess?

A process is a combination of code and data sharing a common virtual address space.
Med prosesser er forskjellige programmer isolert fra hverandre mens de kjører: hver applikasjon bruker sitt eget område i minnet uten å forstyrre andre programmer. For å lære mer, anbefaler jeg å lese denne opplæringen: Prosesser og tråder . En prosess kan ikke eksistere uten en tråd, så hvis en prosess eksisterer, så har den minst én tråd. Men hvordan kommer dette til i Java? Når vi starter et Java-program, begynner kjøringen med mainmetoden. Det er som om vi går inn i programmet, så denne spesielle mainmetoden kalles inngangspunktet. Metoden mainmå alltid være "public static void", slik at Java Virtual Machine (JVM) kan begynne å kjøre programmet vårt. For mer informasjon, Hvorfor er Java-hovedmetoden statisk?. Det viser seg at Java-starteren (java.exe eller javaw.exe) er en enkel C-applikasjon: den laster de forskjellige DLL-ene som faktisk utgjør JVM. Java-starteren foretar et spesifikt sett med Java Native Interface (JNI)-anrop. JNI er en mekanisme for å koble den virtuelle Java-maskinens verden med verden av C++. Så lanseringen er ikke selve JVM, men snarere en mekanisme for å laste den. Den vet de riktige kommandoene som skal utføres for å starte JVM. Den vet hvordan den skal bruke JNI-anrop til å sette opp det nødvendige miljøet. Å sette opp dette miljøet inkluderer å lage hovedtråden, som selvfølgelig kalles "hoved". For bedre å illustrere hvilke tråder som finnes i en Java-prosess, bruker vi jvisualvmverktøyet, som følger med JDK. Når vi kjenner pid-en til en prosess, kan vi umiddelbart se informasjon om den prosessen: jvisualvm --openpid <process id> Bedre sammen: Java og Thread-klassen.  Del I - Tråder om henrettelse - 4Interessant nok har hver tråd sitt eget separate område i minnet som er allokert til prosessen. Denne minnestrukturen kalles en stabel. En stabel består av rammer. En ramme representerer aktiveringen av en metode (et uferdig metodekall). En ramme kan også representeres som et StackTraceElement (se Java API for StackTraceElement ). Du kan finne mer informasjon om minnet som er tildelt hver tråd i diskusjonen her: " Hvordan tildeler Java (JVM) stack for hver tråd ". Hvis du ser på Java API og søker etter ordet "Thread", finner du java.lang.Threadklasse. Dette er klassen som representerer en tråd i Java, og vi må jobbe med den. Bedre sammen: Java og Thread-klassen.  Del I - Utførelsestråder - 5

java.lang.Thread

I Java er en tråd representert av en forekomst av java.lang.Threadklassen. Du bør umiddelbart forstå at forekomster av Thread-klassen ikke i seg selv er utførelsestråder. Dette er bare en slags API for trådene på lavt nivå som administreres av JVM og operativsystemet. Når vi starter JVM ved å bruke Java-starteren, oppretter den en maintråd som kalles "main" og noen få andre husholdningstråder. Som angitt i JavaDoc for Thread-klassen: When a Java Virtual Machine starts up, there is usually a single non-daemon thread. Det er 2 typer tråder: demoner og ikke-demoner. Daemon-tråder er bakgrunnstråder (husholdning) som gjør noe arbeid i bakgrunnen. Ordet "demon" refererer til Maxwells demon. Du kan lære mer i denne Wikipedia-artikkelen . Som angitt i dokumentasjonen, fortsetter JVM å kjøre programmet (prosessen) til:
  • Metoden Runtime.exit () kalles
  • Alle Tråder som ikke er demoner fullfører arbeidet sitt (uten feil eller med kastede unntak)
En viktig detalj følger av dette: daemon-tråder kan avsluttes når som helst. Som et resultat er det ingen garantier for integriteten til dataene deres. Følgelig er demon-tråder egnet for visse husholdningsoppgaver. For eksempel har Java en tråd som er ansvarlig for behandling av finalize()metodekall, dvs. tråder som er involvert med Garbage Collector (gc). Hver tråd er en del av en gruppe ( Trådgruppe ). Og grupper kan være en del av andre grupper, danne et visst hierarki eller struktur.

public static void main(String[] args) {
	Thread currentThread = Thread.currentThread();
	ThreadGroup threadGroup = currentThread.getThreadGroup();
	System.out.println("Thread: " + currentThread.getName());
	System.out.println("Thread Group: " + threadGroup.getName());
	System.out.println("Parent Group: " + threadGroup.getParent().getName());
}
Grupper bringer orden i trådhåndteringen. I tillegg til grupper har tråder sin egen unntaksbehandler. Ta en titt på et eksempel:

public static void main(String[] args) {
	Thread th = Thread.currentThread();
	th.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
		@Override
		public void uncaughtException(Thread t, Throwable e) {
			System.out.println("An error occurred: " + e.getMessage());
		}
	});
    System.out.println(2/0);
}
Divisjon med null vil forårsake en feil som vil bli fanget opp av handleren. Hvis du ikke spesifiserer din egen behandler, vil JVM påkalle standardbehandleren, som vil sende ut unntakets stabelsporing til StdError. Hver tråd har også en prioritet. Du kan lese mer om prioriteringer i denne artikkelen: Java Thread Priority in Multithreading .

Oppretter en tråd

Som det fremgår av dokumentasjonen, har vi 2 måter å lage en tråd på. Den første måten er å lage din egen underklasse. For eksempel:

public class HelloWorld{
    public static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("Hello, World!");  
        }
    }
    
    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();
    }
}
Som du kan se, skjer arbeidet med oppgaven i metoden run(), men selve tråden startes i start()metoden. Ikke forveksle disse metodene: hvis vi kaller r- un()metoden direkte, vil ingen ny tråd startes. Det er start()metoden som ber JVM om å opprette en ny tråd. Dette alternativet der vi arver tråd er allerede dårlig ved at vi inkluderer tråd i klassehierarkiet vårt. Den andre ulempen er at vi begynner å bryte prinsippet om "enkelt ansvar". Det vil si at klassen vår samtidig er ansvarlig for å kontrollere tråden og for en oppgave som skal utføres i denne tråden. Hva er den rette måten? Svaret finnes i samme run()metode, som vi overstyrer:

public void run() {
	if (target != null) {
		target.run();
	}
}
Her targeter noen java.lang.Runnable, som vi kan sende når vi oppretter en forekomst av Thread-klassen. Dette betyr at vi kan gjøre dette:

public class HelloWorld{
    public static void main(String[] args) {
        Runnable task = new Runnable() {
            public void run() {
                System.out.println("Hello, World!");
            } 
        };
        Thread thread = new Thread(task);
        thread.start();
    }
}
Runnablehar også vært et funksjonelt grensesnitt siden Java 1.8. Dette gjør det mulig å skrive enda vakrere kode for en tråds oppgave:

public static void main(String[] args) {
	Runnable task = () -> { 
		System.out.println("Hello, World!");
	};
	Thread thread = new Thread(task);
	thread.start();
}

Konklusjon

Jeg håper denne diskusjonen klargjør hva en tråd er, hvordan tråder blir til, og hvilke grunnleggende operasjoner som kan utføres med tråder. I neste del skal vi prøve å forstå hvordan tråder samhandler med hverandre og utforske trådens livssyklus. Bedre sammen: Java og Thread-klassen. Del II — Synkronisering Bedre sammen: Java og Thread-klassen. Del III — Interaksjon Bedre sammen: Java og Thread-klassen. Del IV — Callable, Future og friends Bedre sammen: Java og Thread-klassen. Del V — Executor, ThreadPool, Fork/Join Better together: Java og Thread-klassen. Del VI – Fyr vekk!
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION