Proste programowanie wielowątkowe

0

Cześć, uczę się Javy z książki "Java. Przewodnik dla początkujących" i jestem na rozdziale z programowania wielowątkowego. Mam taki kod programu, który przedstawia proste zastosowania programowania wielowątkowego:

package cw2;

class MyThread implements Runnable {
  Thread thrd; 

  
  MyThread(String name) {
    thrd = new Thread(this, name); 
    thrd.start();
  }

  
  public void run() {
    System.out.println(thrd.getName() + " rozpoczyna działanie.");
    try {
      for(int count=0; count<10; count++) {
        Thread.sleep(400);
        System.out.println(thrd.getName() +
                           " jest wykonywany, wartość licznika: " + count);
      }
    }
    catch(InterruptedException exc) {
      System.out.println(thrd.getName() + " został przerwany.");
    }
    System.out.println(thrd.getName() + " kończy działanie.");
  }
}


public class Cw2 {

    
    public static void main(String[] args) {
    System.out.println("Główny wątek rozpoczyna działanie.");

    MyThread mt = new MyThread("Wątek potomny nr 1");

    for(int i=0; i < 50; i++) {
      System.out.print(".");
      try {
        Thread.sleep(100);
      }
      catch(InterruptedException exc) {
        System.out.println("Wątek główny został przerwany.");
      }
    }

    System.out.println("Wątek główny kończy działanie.");
    }
    

Pytanie, o co chodzi w poniższej linijce z konstruktora MyThread:

thrd = new Thread(this, name); 

Rozumiem, że do referencji o nazwie thrd jest przypisywany nowy obiekt typu Thread. W nawiasie mamy dwa argumenty: name to rozumiem, że jest nazwa, ale co robi słowo kluczowe this? Przecież to jest samo this, a jeżeli mam być szczery, to nigdy jeszcze nie widziałem takiego zastosowania tego słowa kluczowego.

1

this - słowo kluczowe w javie, referenacja bo "bieżącego" obiektu.

Jak spojrzysz na konstruktory Thread, to masz kilka dwuargumentowych:

Thread(Runnable target, String name)
Thread(ThreadGroup group, Runnable target)
Thread(ThreadGroup group, String name)

"this" odnosi się do bieżącej instancji obiektu klasy MyThread implementującej intefejs Runnable, więc chodzi o konstruktor:
Thread(Runnable target, String name)

Tworzysz wątek, który będzie wywoływał metodę run z klasy MyThread.

1

Jeżeli chcesz uruchomić nowy wątek to potrzebujesz jakiś obiekt który będzie implementowała interfejs Runnable czyli będzie implementował metode run(). W sytuacji kiedy chcesz odpalić nowy wątek

Thread thrd = new Thread(param1, param2)

Musisz podać 2 parametry.

  1. To obiekt który implementuje interface Runnable. Czyli używasz this - te słowo kluczowe wskazuje na referencje do samego siebie
class Obiekt{
private String napis = ""

 public Obiekt(String napis){
  this.napis = napis  
}
}

Jeżeli tworzysz nowy obiekt wywołujesz konstruktor klasy Obiekt i wstawiasz tam parametr new obiekt("Jakiś napis")
no ale konstruktor ma zdefiniowaną zmienna napis jako parametr który ma tą samą nazwę jak właściwość napis na poziomie klasy.
Dlatego na rzecz tego obiektu używasz słowo this aby odwołać się do właściwości na poziomie klasy.
Wiec wiesz że ten obiekt ma zaimplementowany ten interface Runnable no to go ustawiasz

thrd = new Thread(this,"nazwa");

Ten wątek uruchomi metode run() z tej klasy.

0

Dalej nie "czuję tego" w 100%. xd
Czyli mam rozumieć, że pisząc

thrd = new Thread(this, name);

To tworzę obiekt typu Thread, który będzie po prostu wskazywać na instancję klasy MyThread? This wskazuje na referencje do samego siebie, czyli w tym przypadku do tej instancji obiektu MyThread? Następnie w konstruktorze jest wywoływana metoda start(), za pomocą referencji thrd, czyli jest uruchamiana po prostu metoda run() z klasy MyThread.

I jeszcze jedno: w konstruktorze mamy Stringa "name", jednak w samej klasie MyThread nie ma atrybutu typu String. Mam rozumieć, że ten atrybut jest dziedziczony z interfejsu Runnable?

1
kario97 napisał(a):

Dalej nie "czuję tego" w 100%. xd
Czyli mam rozumieć, że pisząc

thrd = new Thread(this, name);

Ten kod wyżej, to to samo co:

MyThread instance = this;
Runnable runnable = instance;
thrd = new Thread(runnable, name);
1
kario97 napisał(a):

Dalej nie "czuję tego" w 100%. xd
Czyli mam rozumieć, że pisząc

thrd = new Thread(this, name);

To tworzę obiekt typu Thread, który będzie po prostu wskazywać na instancję klasy MyThread? This wskazuje na referencje do samego siebie, czyli w tym przypadku do tej instancji obiektu MyThread? Następnie w konstruktorze jest wywoływana metoda start(), za pomocą referencji thrd, czyli jest uruchamiana po prostu metoda run() z klasy MyThread.

Używając wspomnianego konstruktora przekazujesz instancję obiektu, który implementuje interfejs Runnable. W Twoim przypadku MyThread implementuje ten interfejs, więc można przekazaćthis. Równie dobrze mógłbyś przekazać tam instancję innego obiektu implementującego interfejs Runnable. Nie jest po prostu uruchamiana metoda run(), tylko utworzony wątek jest aktywowany. Nie oznacza to, że JVM od razu go wykona.

I jeszcze jedno: w konstruktorze mamy Stringa "name", jednak w samej klasie MyThread nie ma atrybutu typu String. Mam rozumieć, że ten atrybut jest dziedziczony z interfejsu Runnable?

To name masz w konstruktorze MyThread.

0

Zakładamy że tworzysz nowy obiekt swojej klasy MyThread

no to cyk

MyThread nowyWatek = new MyThread("Moj Obiekt ^^")
MyThread nowyWatek2 = new MyThread("Moj Obiekt 2^^")

cyk wywołuję się konstruktor tej klasy

class MyThread implements Runnable {
  Thread thrd; 

  MyThread(String name) {
    thrd = new Thread(this, name); 
    thrd.start();
  }

  public void run() {
   System.out.println("cyk");
  }
}
new Thread(this czyli nowyWatek  , "Moj Obiekt ^^")

new Thread(this czyli nowyWatek2  , "Moj Obiekt2 ^^")
0
kario97 napisał(a):

Dalej nie "czuję tego" w 100%. xd
Czyli mam rozumieć, że pisząc

thrd = new Thread(this, name);

To tworzę obiekt typu Thread, który będzie po prostu wskazywać na instancję klasy MyThread? This wskazuje na referencje do samego siebie, czyli w tym przypadku do tej instancji obiektu MyThread?
Następnie w konstruktorze jest wywoływana metoda start(), za pomocą referencji thrd, czyli jest uruchamiana po prostu metoda run() z klasy MyThread.

Tak, dobrze kombinujesz.

I jeszcze jedno: w konstruktorze mamy Stringa "name", jednak w samej klasie MyThread nie ma atrybutu typu String. Mam rozumieć, że ten atrybut jest dziedziczony z interfejsu Runnable?

Ten atrybut jest w klasie Thread, przecież tworzysz obiekt tej klasy, a nie MyThread, MyThread traktuj jak dawcę samej metody run, ale jej uruchomieniem współbieżnym musi się zająć klasa Thread lub jej klasy potomne.

0

Zamiast używać mylących this na początku, wydziel odpowiedzialności. Masz klasę MyThread, która sama się odpala, czyli sama decyduje o swoim cyklu życia. Taki sam sobie sterem, żeglarzem i okrętem nie jest zbyt dobrym wzorcem projektowym. Masz osobną klasę, która odpala maina. Niech ONA stworzy wątek na podstawie twojej implementacji Runnable.

public class Cw2 {
    public static void main(String[] args) {
    System.out.println("Główny wątek rozpoczyna działanie.");

    Runnable runnable = new MyRunnable();

    Thread mt = new Thread(runnable, "Wątek potomny nr 1");
    //...Reszta bez zmian
}

class MyRunnable implements Runnable { //NIE MyThread, bo Runnable to nie Thread!!!
    //... Wyrzucić ten niepotrzebny konstruktor
  public void run() {
    //...Flaki metody run takie samie
  }
}

W mainie:

  1. Tworzysz obiekt typu Runnable (a dokładnie MyRunnable)
  2. Tworzysz obiekt typu Thread na podstawie nowo stworzonego Runnable.

Twoja poprzednia implementacja robiła dokładnie to samo, tylko... w konstruktorze MyRunnable.
Ale w konstruktorze nie masz zmiennej, która odnosi się do nowo stworzonego obiektu (tak jak tu mamy runnable).
Zamiast tego możesz użyć słowa this, które oznacza TEN obiekt.

1 użytkowników online, w tym zalogowanych: 0, gości: 1