Java Academy · Lekcja

Wątki platformowe a wirtualne

Kiedy używać każdego z nich

Lekcja 3 z 413 kroki

Wątki platformowe a wirtualne to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.

Dwa rodzaje wątków

Java oferuje teraz dwa rodzaje wątków. Wątki platformowe to klasyczne opakowania wokół wątków systemu operacyjnego. Wątki wirtualne są lekkie i zarządzane przez JVM.

Umiejętność rozpoznania, po który rodzaj sięgnąć, jest kluczowa przy tworzeniu skalowalnego współbieżnego kodu w Javie.

Tworzenie wątku platformowego

Wątek platformowy tworzy się za pomocą Thread.ofPlatform(), będącego odpowiednikiem Thread.ofVirtual().

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread p = Thread.ofPlatform().name("native-worker").start(() ->
            System.out.println("Platform? " + !Thread.currentThread().isVirtual()));
        p.join();
    }
}

Porównanie kosztów

Wątki platformowe są ciężkie:

  • Każdy rezerwuje stos o rozmiarze około 1 MB
  • Ich tworzenie jest powolne
  • Ich liczba jest ograniczona do kilku tysięcy

Wątki wirtualne są tanie: mają mały stos początkowy, szybko się je tworzy i możliwe jest używanie ich milionów.

Zadania I/O-bound

Jeśli zadanie spędza większość czasu na oczekiwaniu na sieć, dysk lub bazę danych, wątki wirtualne zapewniają ogromną przewagę.

Gdy jeden wątek wirtualny jest zablokowany, jego wątek nośny może wykonywać inne zadania, dzięki czemu niewielka liczba wątków systemu operacyjnego obsługuje tysiące żądań.

Zadania CPU-bound

W przypadku czystych obliczeń, które nigdy się nie blokują, wątki wirtualne nie zapewniają przyspieszenia. Ogranicza Państwa liczba rdzeni.

W takiej sytuacji właściwym narzędziem jest stała pula o rozmiarze dopasowanym do liczby procesorów.

import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) throws Exception {
        int cores = Runtime.getRuntime().availableProcessors();
        try (ExecutorService cpu = Executors.newFixedThreadPool(cores)) {
            Future<Long> f = cpu.submit(() -> {
                long s = 0;
                for (long i = 0; i < 1_000_000L; i++) s += i;
                return s;
            });
            System.out.println("Cores: " + cores + ", sum: " + f.get());
        }
    }
}

Symulowanie blokowania

Ten fragment pokazuje wiele wątków wirtualnych śpiących jednocześnie, co symuluje blokujące operacje wejścia-wyjścia. Proszę wyobrazić sobie 10 000 wątków platformowych wykonujących to samo.

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class Main {
    public static void main(String[] args) {
        AtomicInteger done = new AtomicInteger();
        try (ExecutorService exec = Executors.newVirtualThreadPerTaskExecutor()) {
            for (int i = 0; i < 10_000; i++) {
                exec.submit(() -> {
                    try { Thread.sleep(50); } catch (InterruptedException e) {}
                    done.incrementAndGet();
                });
            }
        }
        System.out.println("Finished blocking tasks: " + done.get());
    }
}

Status demona

Wątki wirtualne są zawsze wątkami demona i nie można zmienić ich na wątki niedemonowe. Wątki platformowe domyślnie dziedziczą status demona po twórcy, ale można ustawić go jawnie.

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread v = Thread.ofVirtual().unstarted(() -> {});
        Thread p = Thread.ofPlatform().unstarted(() -> {});
        System.out.println("virtual daemon: " + v.isDaemon());
        System.out.println("platform daemon: " + p.isDaemon());
    }
}

Priorytety są ignorowane

Wątki wirtualne zawsze zgłaszają priorytet NORM_PRIORITY, a jego ustawienie nie przynosi żadnego skutku. Za planowanie odpowiada JVM, a nie planista systemu operacyjnego.

public class Main {
    public static void main(String[] args) {
        Thread v = Thread.ofVirtual().unstarted(() -> {});
        v.setPriority(Thread.MAX_PRIORITY);
        System.out.println("Priority is still: " + v.getPriority());
    }
}

Wskazówka dotycząca wyboru

Praktyczna zasada jest następująca:

  • Wiele zadań, które czekają na operacje wejścia-wyjścia? Należy użyć wątków wirtualnych.
  • Intensywne obliczenia ograniczone przez procesor? Należy użyć stałej puli wątków platformowych.
  • Potrzebne jest dostrajanie wątków na poziomie systemu operacyjnego, na przykład priorytetu lub afinity? Należy użyć wątków platformowych.

Mogą współistnieć

Nie trzeba wybierać jednego rodzaju dla całego programu. Typowa aplikacja używa wątków wirtualnych do obsługi żądań oraz niewielkiej puli wątków platformowych do sekcji intensywnie obciążających procesor.

Oba rodzaje korzystają z tego samego interfejsu API Thread, więc ich łączenie jest bezproblemowe.

Wskazówka dotycząca migracji

Podczas przenoszenia usługi intensywnie korzystającej z operacji wejścia-wyjścia najmniejsza zmiana polega na zamianie executora: należy zastąpić stałą lub buforowaną pulę wywołaniem newVirtualThreadPerTaskExecutor().

Należy tylko uważać na przypinanie oraz niewłaściwe użycie ThreadLocal — te zagadnienia omówimy w następnej lekcji.

Szybkie sprawdzenie

Wybierz obciążenie, w przypadku którego wątki wirtualne zapewniają najbardziej wyraźną korzyść.

Podsumowanie

Porównali Państwo dwa modele wątków:

  • Wątki platformowe: ciężkie, oparte na wątkach systemu operacyjnego, najlepsze do zadań CPU-bound i dostrajania na poziomie systemu operacyjnego
  • Wątki wirtualne: tanie, zarządzane przez JVM, zawsze będące demonami, najlepsze do współbieżnych zadań I/O-bound
  • Mogą współistnieć i korzystają z tego samego interfejsu API

W następnej części: pułapki związane z przypinaniem i ThreadLocal.

Bezpłatny start

Ucz się Java dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
104
Lekcje
374

Często zadawane pytania

Czy lekcja „Wątki platformowe a wirtualne” jest bezpłatna?

Tak — pełny tekst „Wątki platformowe a wirtualne” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Wątki platformowe a wirtualne”?

Kiedy używać każdego z nich Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Java Academy?

Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Wątki platformowe a wirtualne”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?

Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Czym są wirtualne wątki
  2. Tworzenie wirtualnych wątków
  3. Wątki platformowe a wirtualne
  4. Pułapki: przypinanie i ThreadLocal
← Powrót do Java Academy