2355 Stimmen

"implementiert Runnable" vs. "erweitert Thread" in Java

Nach der Zeit, die ich mit Threads in Java Ich habe diese beiden Möglichkeiten gefunden, Themen zu schreiben:

Mit implementiert Runnable :

public class MyRunnable implements Runnable {
    public void run() {
        //Code
    }
}
//Started with a "new Thread(new MyRunnable()).start()" call

Oder, mit erweitert Thread :

public class MyThread extends Thread {
    public MyThread() {
        super("MyThread");
    }
    public void run() {
        //Code
    }
}
//Started with a "new MyThread().start()" call

Gibt es einen signifikanten Unterschied zwischen diesen beiden Codeblöcken?

66 Stimmen

Vielen Dank für diese Frage, die Antworten haben eine Menge Missverständnisse, die ich hatte, aufgeklärt. Ich schaute in den richtigen Weg, um Java-Threads zu tun, bevor SO existierte und es gab eine Menge von Fehlinformationen / veraltete Informationen da draußen.

5 Stimmen

Gibt es einen Grund, warum Sie den Thread ( aber ich empfehle es nicht ), können Sie präventiv mit interrupt() . Auch hier handelt es sich um eine Idee, die im richtigen Fall nützlich sein könnte, aber ich empfehle sie nicht.

0 Stimmen

Bitte lesen Sie auch die Antwort, die sehr gut erklärt ist: stackoverflow.com/q/5562720/285594

4voto

Vishal Punkte 786

Ein Unterschied zwischen der Implementierung von Runnable und der Erweiterung von Thread besteht darin, dass bei der Erweiterung von Thread jedem Ihrer Threads ein eigenes Objekt zugeordnet ist, während bei der Implementierung von Runnable viele Threads dieselbe Objektinstanz nutzen können.

Eine Klasse, die Runnable implementiert, ist kein Thread, sondern nur eine Klasse. Damit eine Runnable von einem Thread ausgeführt werden kann, müssen Sie eine Instanz von Thread erstellen und die Runnable-Instanz als Ziel übergeben.

In den meisten Fällen sollte die Runnable-Schnittstelle verwendet werden, wenn Sie nur die run()-Methode und keine anderen Thread-Methoden außer Kraft setzen wollen. Dies ist wichtig, weil Klassen nicht unterklassifiziert werden sollten, es sei denn, der Programmierer beabsichtigt, das grundlegende Verhalten der Klasse zu ändern oder zu verbessern.

Wenn es notwendig ist, eine Oberklasse zu erweitern, ist die Implementierung der Runnable-Schnittstelle besser geeignet als die Verwendung der Thread-Klasse. Denn wir können eine andere Klasse erweitern, während wir die Runnable-Schnittstelle implementieren, um einen Thread zu erstellen. Wenn wir aber nur die Thread-Klasse erweitern, können wir von keiner anderen Klasse erben.

4voto

JayC667 Punkte 1792

Für die meisten Worker-Threads ist es am besten, wenn das Threading vollständig in der Worker-Klasse gekapselt ist, damit nichts von außen eingreifen und unerwünschte und ungültige Thread-/Klassenzustände verursachen kann.

Ich habe gerade ein Beispiel gepostet, also werde ich auch dieses mit Ihnen teilen:

/**
 * This worker can only run once
 * @author JayC667
 */
public class ProperThreading {

    private final Thread        mThread         = new Thread(() -> runWorkingLoop());   // if you want worker to be able to run multiple times, move initialisation into startThread()
    private volatile boolean    mThreadStarted  = false;
    private volatile boolean    mStopRequested  = false;

    private final long          mLoopSleepTime;

    public ProperThreading(final long pLoopSleepTime /* pass more arguments here, store in members */ ) {
        mLoopSleepTime = pLoopSleepTime;
    }

    public synchronized void startThread() {
        if (mThreadStarted) throw new IllegalStateException("Worker Thread may only be started once and is already running!");
        mThreadStarted = true;
        mThread.start();
    }

    private void runWorkingLoop() {
        while (!mStopRequested /* && other checks */ ) {
            try {
                // do the magic work here
                Thread.sleep(mLoopSleepTime);

            } catch (final InterruptedException e) {
                break;
            } catch (final Exception e) {
                // do at least some basic handling here, you should NEVER ignore exception unless you know exactly what you're doing, and then it should be commented!
            }
        }
    }

    public synchronized void stopThread() {
        if (!mThreadStarted) throw new IllegalStateException("Worker Thread is not even running yet!");
        mStopRequested = true;
        mThread.interrupt();
    }

}

3voto

Peter Lawrey Punkte 511323

Der Thread enthält Verhaltensweisen, auf die nicht zugegriffen werden soll;

  • seine synchronisierte Sperre wird für die Verknüpfung usw. verwendet.
  • es hat Methoden, auf die Sie zufällig zugreifen können.

jedoch, wenn Sie Sub-Klasse Thread haben zu berücksichtigen, mehr Thread implementiert ist.

public class ThreadMain {
    public int getId() {
        return 12345678;
    }

    public String getName() {
        return "Hello World";
    }

    public String getState() {
        return "testing";
    }

    public void example() {
        new Thread() {
            @Override
            public void run() {
                System.out.println("id: "+getId()+", name: "+getName()+", state: "+getState());
            }
        }.start();
    }

    public static void main(String[] args) {
        new ThreadMain().example();
    }
}

Wenn Sie dies ausführen, können Sie Folgendes erwarten

id: 12345678, name: Hello World, state: testing

Sie rufen jedoch nicht die Methoden auf, von denen Sie glauben, dass Sie sie aufrufen, weil Sie die Methode in Thread no ThreadMain und stattdessen sehen Sie etwas wie

id: 11, name: Thread-0, state: RUNNABLE

3voto

Arasn Punkte 128

1. Das Erweitern der Thread-Schnittstelle bedeutet, dass Sie Ihre Klasse so gestalten, dass sie sich nur wie ein Thread verhält. Ihre neue Klasse wird wie ein erweiterter Thread sein.

jshell> public class Test extends Thread{
   ...> public Test(String name){
   ...> super(name);
   ...> }
   ...> public void run(){
   ...> System.out.println(Thread.currentThread().getName());
   ...> }
   ...> }
|  created class Test

jshell> Test t1=new Test("MyThread");
t1 ==> Thread[MyThread,5,main]

Es wird ein Thread erstellt, nicht der Test Objekt. Es wird sich also wie ein einzelner Thread verhalten. Sie können die Instanz von Test Klasse zwischen Threads.

2. Implementierung der runnable-Schnittstelle.

jshell> public class Test1 implements Runnable{
   ...> public void run(){
   ...> System.out.println(Thread.currentThread().getName());
   ...> }
   ...> public String getName(){
   ...> return "testing";}
   ...> }
|  created class Test1

jshell> Test1 t1=new Test1();
t1 ==> Test1@396a51ab  --> this creates Test1 object.

Dieses Objekt kann von mehreren Threads gemeinsam genutzt werden,

jshell> Thread t1=new Thread(t1,"Hai");
t ==> Thread[Hai,5,main]

jshell> Thread t=new Thread(t1,"Hai");
t ==> Thread[Hai,5,main]

Ich denke, es wurde bereits viel zu diesem Thema diskutiert, aber ich dachte, dies könnte hilfreich sein, um die Grundlagen zu vermitteln.

2voto

AHugoH Punkte 63

Dies ist vielleicht keine Antwort, aber es gibt noch eine weitere Möglichkeit, Themen zu erstellen:

Thread t = new Thread() {
    public void run() {
        // Code here
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X