Współbieżność Java - omówienie
Java to wielowątkowy język programowania, co oznacza, że możemy tworzyć wielowątkowe programy przy użyciu języka Java. Program wielowątkowy zawiera dwie lub więcej części, które mogą działać jednocześnie, a każda część może jednocześnie obsługiwać inne zadanie, optymalnie wykorzystując dostępne zasoby, szczególnie gdy komputer ma wiele procesorów.
Z definicji wielozadaniowość to sytuacja, w której wiele procesów korzysta ze wspólnych zasobów przetwarzania, takich jak procesor. Wielowątkowość rozszerza ideę wielozadaniowości na aplikacje, w których można podzielić określone operacje w ramach jednej aplikacji na osobne wątki. Każdy z wątków może działać równolegle. System operacyjny dzieli czas przetwarzania nie tylko na różne aplikacje, ale także na każdy wątek w aplikacji.
Wielowątkowość umożliwia pisanie w taki sposób, że wiele działań może być wykonywanych jednocześnie w tym samym programie.
Cykl życia wątku
Wątek przechodzi przez różne etapy swojego cyklu życia. Na przykład wątek rodzi się, uruchamia, działa, a następnie umiera. Poniższy diagram przedstawia pełny cykl życia wątku.
Oto etapy cyklu życia -
New- Nowy wątek rozpoczyna swój cykl życia w nowym stanie. Pozostaje w tym stanie, dopóki program nie uruchomi wątku. Jest również określany jako plikborn thread.
Runnable- Po uruchomieniu nowo powstałego wątku wątek staje się gotowy do uruchomienia. Uważa się, że wątek w tym stanie wykonuje swoje zadanie.
Waiting- Czasami wątek przechodzi w stan oczekiwania, podczas gdy wątek oczekuje na wykonanie zadania przez inny wątek. Wątek przechodzi z powrotem do stanu, który można uruchomić, tylko wtedy, gdy inny wątek sygnalizuje oczekującemu wątkowi, aby kontynuował wykonywanie.
Timed Waiting- Działający wątek może wejść w czasowy stan oczekiwania przez określony przedział czasu. Wątek w tym stanie przechodzi z powrotem do stanu, który można uruchomić, po wygaśnięciu tego przedziału czasu lub gdy wystąpi zdarzenie, na które oczekuje.
Terminated (Dead) - Wątek, który można uruchomić, przechodzi w stan przerwania po zakończeniu zadania lub w inny sposób.
Priorytety wątków
Każdy wątek Java ma priorytet, który pomaga systemowi operacyjnemu określić kolejność planowania wątków.
Priorytety wątków Java są w zakresie od MIN_PRIORITY (stała 1) do MAX_PRIORITY (stała 10). Domyślnie każdy wątek ma priorytet NORM_PRIORITY (stała 5).
Wątki o wyższym priorytecie są ważniejsze dla programu i powinny mieć przydzielony czas procesora przed wątkami o niższym priorytecie. Jednak priorytety wątków nie mogą zagwarantować kolejności wykonywania wątków i są bardzo zależne od platformy.
Utwórz wątek, implementując uruchamialny interfejs
Jeśli twoja klasa ma być wykonywana jako wątek, możesz to osiągnąć, implementując plik Runnableberło. Będziesz musiał wykonać trzy podstawowe kroki -
Krok 1
Pierwszym krokiem jest zaimplementowanie metody run () udostępnianej przez plik Runnableberło. Ta metoda zapewnia punkt wejścia dla wątku, a całą logikę biznesową umieścisz w tej metodzie. Poniżej znajduje się prosta składnia metody run () -
public void run( )
Krok 2
W drugim kroku utworzysz instancję Thread obiekt przy użyciu następującego konstruktora -
Thread(Runnable threadObj, String threadName);
Gdzie threadObj jest wystąpieniem klasy, która implementujeRunnable interfejs i threadName to nazwa nadana nowemu wątkowi.
Krok 3
Po utworzeniu obiektu Thread możesz go uruchomić, wywołując start()metoda, która wykonuje wywołanie metody run (). Poniżej znajduje się prosta składnia metody start () -
void start();
Example
Oto przykład, który tworzy nowy wątek i uruchamia go -
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo(String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo("Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo("Thread-2");
R2.start();
}
}
To da następujący wynik -
Output
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Utwórz wątek, rozszerzając klasę wątku
Drugim sposobem na utworzenie wątku jest utworzenie nowej klasy, która rozszerza Threadw dwóch prostych krokach. Takie podejście zapewnia większą elastyczność w obsłudze wielu wątków utworzonych przy użyciu metod dostępnych w klasie Thread.
Krok 1
Będziesz musiał zmienić run( )metoda dostępna w klasie Thread. Ta metoda zapewnia punkt wejścia dla wątku, a całą logikę biznesową umieścisz w tej metodzie. Poniżej znajduje się prosta składnia metody run () -
public void run( )
Krok 2
Po utworzeniu obiektu Thread możesz go uruchomić, wywołując start()metoda, która wykonuje wywołanie metody run (). Poniżej znajduje się prosta składnia metody start () -
void start( );
Example
Oto poprzedni program przepisany w celu rozszerzenia wątku -
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo(String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo("Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo("Thread-2");
T2.start();
}
}
To da następujący wynik -
Output
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.