2010-04-07 7 views
6

Ok, so che le due modalità standard per creare un nuovo thread ed eseguirlo in Java:Java - Chiama per avviare il metodo sul thread: come si dirige verso runnable dell'interfaccia run()?

  1. Implementare Runnable in una classe, definire run() metodo e passare un'istanza della classe per una nuova Thread. Quando viene chiamato il metodo start() sull'istanza thread, viene richiamato il metodo run dell'istanza di classe.

  2. Lasciate che la classe derivano da Thread, in modo che possa eseguire l'override del metodo run() e poi, quando il metodo start() una nuova dell'istanza viene chiamato, la chiamata viene instradata al metodo di override.

In entrambi i metodi, in pratica viene creato un nuovo oggetto Thread e viene richiamato il suo metodo di avvio. Tuttavia, mentre nel secondo metodo, il meccanismo della chiamata che viene instradato al metodo definito dall'utente run() è molto chiaro, (è un polimorfismo di runtime semplice in riproduzione), non capisco come chiamare il metodo start() sull'oggetto Thread viene instradato al metodo run() della classe che implementa l'interfaccia Runnable. La classe Thread ha un campo privato di tipo Runnable che controlla per primo e se è impostato richiama il metodo run se è impostato su un oggetto? quello sarebbe uno strano meccanismo IMO.

In che modo la chiamata a start() su un thread viene instradata al metodo di esecuzione dell'interfaccia Runnable implementata dalla classe il cui oggetto viene passato come parametro durante la costruzione del thread?

risposta

7

Thread mantiene un riferimento all'istanza Runnable e lo chiama nell'implementazione di base di run.

Si può vedere questo nella fonte:

// passed into the constructor and set in the init() method 
private Runnable target; 
... 
// called from native thread code after start() is called 
public void run() { 
    if (target != null) { 
     target.run(); 
    } 
} 
+0

Presumibilmente questo sarà spesso un riferimento a "questo" come nel 2o metodo? – Finbarr

+0

Questo non risponde alla sua domanda. Se si deriva da Thread, il riferimento Runnable, chiamato target nell'origine, è nullo. –

+0

@Frederik: Sì, ma dal momento che si esegue l'override di 'run', non accadrà nulla. – SLaks

1

In entrambi i casi ci deve essere classe Thread concreta. Nel primo caso (implementando un Runnable), rende la classe che lo implementa capace di "essere" un thread. Devi ancora passare la tua classe come argomento al costruttore della classe Thread. Considerando che questo non è lo scenario nel secondo caso in cui si estende una classe Thread.

Quando viene chiamato un metodo start(), non vi è alcuna garanzia che il metodo run() venga immediatamente richiamato. Chiamare un metodo start() indica che il thread è pronto per essere eseguito. Può andare in uno qualsiasi degli stati successivi a seconda del pooler Thread.

FYI: class Thread implements Runnable

1

Si potrebbe avere appena controllato la fonte di Thread.java incluso come parte del JDK:

public void run() { 
    if (target != null) { 
     target.run(); 
    } 
} 

dove target è:

private Runnable target; 

ma penso che il vero la risposta che stai cercando sono i dettagli su come funzionano davvero le discussioni. Questo è sfortunatamente rimosso nelle librerie native. Basta provare ad avere una comprensione di alto livello di come funziona la filettatura.

2

Mentre si può guardare il codice sorgente, a occhio e croce, sarebbe qualcosa di simile:

public class MyThread implements Runnable { 
private Runnable r; 
public MyThread() { 
} 
public MyThread(Runnable r) { 
     this.r = r; 
} 

public void start() { 
    //magic to launch a new thread 
    run(); // the above magic would probably call run(), rather than 
      // call it directly here though. 
    } 
    public void run() { 
    if(r != null) 
     r.run(); 
    } 
} 

In breve, se si estende MyThread e ignorare run(), il metodo della corsa() sarebbe chiamato. Se invece hai passato un Runnable, il metodo run() di MyThread delegherebbe solo al metodo run() di quel Runnable.

+0

purtroppo * inserire la magia qui * è la spiegazione più semplice – Pyrolistical

+1

La tua ipotesi è completamente corretta, tranne che 'r' è chiamato' target', e che il costruttore chiama un metodo 'init' che lo imposta. – SLaks

1

L'unica cosa che non è stata ancora esplorata dalle risposte è come le cose vanno da start() a run(), che è allo stesso tempo sia semplice che complesso.

In termini semplicistici, il metodo start() chiama un metodo nativo (start0 nell'attuazione OpenJDK) che alloca alcuna memoria per una nuova pila e chiede al sistema operativo di eseguire un thread con tale spazio come stack e con una semplice funzione C++ (thread_entry nell'implementazione OpenJDK) come funzione di implementazione. Questa funzione a sua volta rimanda il junk in Java per chiamare il metodo run() sull'oggetto Thread. Il pattern a basso livello (chiedendo al sistema operativo di avviare un nuovo thread su uno stack e con una funzione) dovrebbe essere familiare a chiunque esegua thread nativi in ​​sistemi POSIX o Windows.

Il dettaglio rende tutto molto più complesso, con tutti i casi di gestione degli errori e di bordi oscuri che devono essere gestiti. Se sei curioso, leggi le fonti OpenJDK, prestando particolare attenzione a Thread.java, JVM_StartThread in jvm.cpp e la classe JavaThread in thread.cpp e thread.hpp. Speriamo che questa risposta ti fornisca abbastanza dettagli per trovare la tua strada ...

Problemi correlati