2010-04-22 19 views
6

¿O sí?
Tengo un objeto hilo de:¿Por qué no se llama inmediatamente a run() cuando start() invoca un objeto de subproceso en java

Thread myThread = new Thread(pObject); 

Dónde pObject es un objeto de una clase que implementa la interfaz Ejecutable y luego tengo el método de inicio del pedido al objeto hilo de esta manera:

myThread.start(); 

Ahora, entiendo que cuando se invoca start(), la JVM llama implícitamente (e inmediatamente) al método run() que puede anularse (como es en mi caso)

Sin embargo, en mi caso, aparece que el comienzo() método no es llamado inmediatamente (según se desee), pero hasta que los otros estados/métodos se completó Del es decir bloque de llamada si tuviera un método después del inicio() llamar así:

myThread.start(); 
doSomethingElse(); 

doSomthingElse() será ejecutado antes el método run() se ejecuta en absoluto.
Quizás estoy equivocado con la premisa inicial de que ejecutar() siempre se llama justo después de que se invoca start(). ¡Por favor ayuda! Lo deseado de nuevo es hacer ejecutar run() justo después de start(). Gracias.

+0

Puede llamar 'Thread.yield()' para "liberar" la CPU para otros hilos, pero eso no significa que usted nuevo hilo es la siguiente. – Progman

Respuesta

10

Ahora, mi entendimiento es que cuando inicio() se llama, la JVM de forma implícita (y de inmediato) llama al método run() ...

Eso es incorrecto. Llama implícitamente al run(), pero la llamada no ocurre necesariamente de inmediato.

La realidad es que el nuevo hilo esté disponible para ser programado en algún momento en el tiempo después de que se hizo la llamada start(). La programación real depende del programador nativo. Podría suceder inmediatamente, o el hilo padre podría continuar por un período antes de que el hilo hijo esté programado.

Para forzar que el hilo comience a ejecutarse inmediatamente (o para ser más preciso, para empezar a ejecutar antes del doSomethingElse()), necesita hacer una sincronización explícita; p.ej. algo como esto:

java.util.concurrent.CountDownLatch latch = new CountdownLatch(1); 
    new Thread(new MyRunnable(latch)).start(); 
    latch.await(); // waits until released by the child thread. 
    doSomethingElse(); 

donde

class MyRunnable implements Runnable { 
    private CountDownLatch latch; 
    MyRunnable (CountDownLatch latch) { this.latch = latch; } 
    public void run() { 
     doSomeStuff(); 
     latch.countDown(); // releases the parent thread 
     doSomeMoreStuff(); 
    } 
    ... 
} 

Hay otras maneras de implementar la sincronización utilizando las clases de concurrencia o exclusión mutua de Java/wait/notify primitivas . Pero la sincronización explícita entre los dos hilos es la única forma de garantizar el comportamiento que necesita.

Tenga en cuenta que la llamada doSomething() en el subproceso secundario se completará antes de que se libere el subproceso principal, pero no podemos decir nada sobre el orden de ejecución de doSomethingElese() y doSomeMoreStuff(). (Uno podría correr antes de la otra y viceversa, o pueden funcionar en paralelo.)


1 - Usando wait/notify no es recomendable, pero puede ser su única opción si las API de concurrencia no son disponible; p.ej. en Java ME.

12

run() es lo primero dentro de su código que hace el nuevo hilo, pero hay algo de trabajo de configuración que el nuevo hilo hace primero, y no hay garantía de que el nuevo hilo haga una cantidad significativa de trabajo antes el hilo original continúa para llamar al doSomethingElse().

Tiene razón al pensar que no hay garantías aquí. Hacer suposiciones sobre el comportamiento del código multiproceso es la fuente de mucho dolor, ¡trate de no hacerlo!

+1

+1 "Hacer suposiciones sobre el comportamiento del código multiproceso es la fuente de mucho dolor, ¡trate de no hacerlo!" – Yaneeve

15

Um ... el método run() ejecutará en un hilo diferente. Eso, por definición, significa que no puede hacer supuestos acerca de antes o después de qué enunciados en el hilo actual se ejecutará, a menos que los sincronice explícitamente.

3

Has comenzado un nuevo hilo. Ese hilo corre en paralelo al hilo que lo inició lo que el orden podría ser:

pObject.run(); 
doSomethingElse(); 

o

doSomethingElse(); 
pObject.run(); 

o, más probablemente, habrá algún cruce. pObject.run() puede ejecutarse en el medio de doSomethingElse() o viceversa o uno comenzará antes de que el otro termine y así sucesivamente. Es importante entender esto y entender qué se entiende por operación atómica o te encontrarás con algunos errores realmente difíciles de encontrar.

Es aún más complicado si dos o más hilos acceden a las mismas variables. El valor en uno puede nunca actualizarse en un hilo bajo ciertas circunstancias.

le recomiendo:

  1. Usted No hacer su programa multi-hilo a menos que absolutamente necesario; y

  2. Si lo hace, compre y lea de principio a fin Java Concurrency in Practice de Brian Goetz.

+0

* "Ese hilo se ejecuta en paralelo al hilo que lo inició ..." *. No necesariamente.Por ejemplo, en una plataforma donde solo hay un núcleo (y no hay hyperthreading) la ejecución de los dos hilos puede estar intercalada, pero no es posible que se ejecuten en paralelo. –

6

Cuando llame al myThread.start(), su hilo estará disponible para su ejecución. Si realmente ganará CPU, y por cuánto tiempo, estará en el programador del sistema operativo. De hecho, su run() puede obtener control inmediatamente, pero perderlo antes de que pueda hacer cualquier cosa que pueda notar. La única forma de asegurarse de que su hilo ejecuta lo que necesita antes de doSomethingElse() es usar sincronización explícita.

Cuestiones relacionadas