Jason. Cała informatyka w jednym miejscu!

Lecimy dalej naprzód z wątkami w Javie! Dzisiaj skonfrontujemy oba sposoby tworzenia wątków. Jest możliwość zrobienia tego od strony dziedziczenia klasy "Thread", ale mamy również do dyspozycji implementację interfejsu "Runnable" w języku Java. Którą drogę wybrać? Czy są jakieś różnice w działaniu? A może w efektywności? Przekonajcie się już teraz.

TWORZENIE WĄTKU PRZY UŻYCIU KLASY "THREAD" W JĘZYKU JAVA

Wątek może zostać utworzony na dwa sposoby. Jedną z dróg jest stworzenie wątku przez dziedziczenie klasy "Thread". Zwyczajnie tworzymy sobie nową klasę i dopisujemy "extends Thread". Potem przesłaniamy metodę "run" i od tej chwili możemy pisać dowolne polecenia jakie się mają wykonać po uruchomieniu tego wątku. Plusem jest to, że nie ma odseparowania zadania od wątku, czyli części wykonawczej od uruchomieniowej. Minus jest dosyć dotkliwy, pozbawiacie się możliwości rozszerzania o dowolną inną klasę! Przypominam, że Java nie zezwala na wielokrotne dziedziczenie i na podstawie jednego z poprzednich artykułów udowodniłem dlaczego.

Struktura "kodowa" wygląda prosto:

public class NewClass extends Thread
{
	@Override
	public void run()
	{
		// polecenia
	}
}

W środku metody "run" określamy polecenia tak samo, jak robiliśmy to poprzednio w "Runnable", tylko że wszystko jest w jednym miejscu. Następnie tworzycie sobie instancję tak jak zwykle i wystarczy wywołać metodę "start":

NewClass nc = new NewClass();

nc.start();

TWORZENIE WĄTKU PRZY UŻYCIU INTERFEJSU "RUNNABLE" W JĘZYKU JAVA

Druga możliwość polega na zaimplementowaniu interfejsu "Runnable" do klasy i przesłonięcie metody "run" (które teraz jest OBOWIĄZKOWE) i wstawienie tam dowolnych poleceń. Osobiście radziłbym skorzystanie z tej metody ze względu na fakt, iż w razie potrzeby, mogę sobie implementować jeszcze więcej interfejsów, a wolne miejsce na potencjalne dziedziczenie wciąż istnieje.

Tak wygląda wątek w Java w klasie "wspieranej" za pomocą interfejsu:

public class NewClass implements Runnable
{
	@Override
	public void run()
	{
		// polecenia
	}
}

Tworzymy sobie później obiekt na jej podstawie i "podpinamy" to pod osobny obiekt klasy "Thread", a resztę już znacie:

Thread thread = new Thread(new NewClass());

thread.start();

PRZYKŁAD KODU ŹRÓDŁOWEGO

Na koniec zostawiam Wam przykład kodu źródłowego który skompilowany, uruchomi dwa wątki w tym samym czasie. Jeden wątek w Java został utworzony przez dziedziczenie klasy "Thread", a drugi poprzez implementację interfejsu "Runnable" w języku Java. Radzę uważnie obserwować wyniki. Wypisy tekstów na konsolę pokażą bardzo ważne zjawisko polegające na "ściganiu się" wątków. W efekcie końcowym ujrzycie losową kolejność występowania komunikatów co każdą iterację.

KLASA "MAIN"

public class Main
{
	public static void main(String[] args)
	{
		new Launcher();
	}
}

KLASA "LAUNCHER"

public class Launcher
{
	public Launcher()
	{
		ThreadFromInterface tfi = new ThreadFromInterface();
		ThreadFromClass tfc = new ThreadFromClass();
		Thread threadForInterface = new Thread(tfi);

		tfc.start();
		threadForInterface.start();
	}
}

KLASA "THREADFROMCLASS"

public class ThreadFromClass extends Thread
{
	@Override
	public void run()
	{
		try
		{
			for (int i = 1; i <= 5; ++i)
			{
				System.out.println("Iteracja #" + i + " z wątku z klasy");
				Thread.sleep(1000);
			}

			System.out.println("Koniec z wątku z klasy!");
		}
		catch (Exception exception)
		{
			exception.printStackTrace();
		}
	}
}

KLASA "THREADFROMINTERFACE"

public class ThreadFromInterface implements Runnable
{
	@Override
	public void run()
	{
		try
		{
			for (int i = 1; i <= 5; ++i)
			{
				System.out.println("Iteracja #" + i + " z wątku z interfejsu");
				Thread.sleep(1000);
			}

			System.out.println("Koniec z wątku z interfejsu!");
		}
		catch (Exception exception)
		{
			exception.printStackTrace();
		}
	}
}

Najlepiej będzie jak to sobie skompilujecie i uruchomicie sami. Nie stwierdzono żadnych różnic w płynności działania przy użyciu jednej i drugiej metody. Można korzystać z obu bez żadnych obaw o "performance". I jeszcze jedno. W celu spowodowania opóźnienia działania obu wątków wykorzystałem statyczną metodę "sleep" z klasy "Thread". Nie powinno się uzależniać kolejności wykonywania od jej wywołań.

Działanie dwóch wątków naraz w języku Java

Tak MOGĄ wyglądać wyniki działania obu wątków jednocześnie! MOGĄ, bo wątki będą się "ścigać" który z nich jako pierwszy będzie mógł wykonać swoje zadanie.


Tak oto zakończyliśmy kolejny fragment większego rozdziału ukazujący jak się tworzy i prezentuje wątek przy użyciu interfejsu "Runnable" w języku Java oraz klasy "Thread". Potrenujcie sobie sami, tylko tak zrozumienie szybciej przyjdzie do głów.

PODOBNE ARTYKUŁY