2012-05-18 5 views
7

Solo soy un principiante en Java y he tropezado con aplicaciones de subprocesos múltiples. Sé que esta pregunta es similar a algunas publicaciones aquí, pero no pude encontrar una mejor respuesta para mi consulta. Básicamente, quiero pasar un objeto a un método estático y el método simplemente devolverá un resultado basado en los valores/propiedades del objeto. Para cada llamada, estoy creando una nueva instancia del objeto y no hay ninguna posibilidad de que modifique el objeto dentro del método. Ahora, mi pregunta es, ¿creará JVM una nueva instancia del método estático y sus variables locales en la pila (excluyendo el objeto tal como estará en el montón) para cada llamada por múltiples hilos? Para una visión clara de lo que quiero lograr, aquí está mi código:Varios hilos que pasan una referencia de objeto al método de ayudante estático

TestConcurrent.java

import classes.Player; 

public class TestConcurrent 
{ 
    private static int method(Player player) 
    { 
     int y = (player.getPoints() * 10) + 1; 

      try { 
        Thread.sleep(1000); 
      } catch (InterruptedException e) {} 

      return ++y; 
    } 

    public static void main(String[] args) throws Exception 
    { 
     // Create 100 threads 
     for(int i=1;i<=100;i++) 
     { 
      final int j = i; 
      // Create a new Thread 
      new Thread() 
      { 
       public void run() 
       { 
        // Create a new instance of the Player class 
        Player player = new Player(j,j,"FirstName" + j, "LastName" + j); 
        // Call static method() and pass a new instance of Player class 
        System.out.println("Thread " + j + ": " + TestConcurrent.method(player)); 
        // Check the values of the Player class after the call to the static method() 
        System.out.println("Player" + player.getAcctId() + " : Points=" + player.getPoints() + " Name=" + player.getFirstName() + " " + player.getLastName()); 
       } 
      }.start(); 
     } 
    } 

} 

Player.java

package classes; 

public class Player 
{ 
    private int acctId, points; 
    String firstName, lastName; 

    public Player(int acctId, int points, String firstName, String lastName) 
    { 
     this.acctId = acctId; 
     this.points = points; 
     this.firstName = firstName; 
     this.lastName = lastName; 
    } 

    public int getAcctId() { 
     return acctId; 
    } 
    public void setAcctId(int acctId) { 
     this.acctId = acctId; 
    } 
    public int getPoints() { 
     return points; 
    } 
    public void setPoints(int points) { 
     this.points = points; 
    } 
    public String getFirstName() { 
     return firstName; 
    } 
    public void setFirstName(String firstName) { 
     this.firstName = firstName; 
    } 
    public String getLastName() { 
     return lastName; 
    } 
    public void setLastName(String lastName) { 
     this.lastName = lastName; 
    } 
} 

SALIDA:

Como no puse una palabra clave sincronizada, th La salida será diferente cada vez y se ve similar a lo siguiente: (la salida es correcta y es exactamente lo que estoy esperando, solo quiero aclarar que estoy en el camino correcto ya que no quiero usar la sincronización como que se ralentizará el proceso, porque cada hilo tendrá que esperar a que el otro hilo para terminar antes de que pueda llamar al método estático)

Thread 2: 22 
Player8 : Points=8 Name=FirstName8 LastName8 
Thread 22: 222 
Thread 26: 262 
Thread 23: 232 
Player23 : Points=23 Name=FirstName23 LastName23 
Thread 21: 212 
Player21 : Points=21 Name=FirstName21 LastName21 
Thread 25: 252 
Player25 : Points=25 Name=FirstName25 LastName25 
Thread 20: 202 
Thread 19: 192 
Thread 24: 242 
Player24 : Points=24 Name=FirstName24 LastName24 
Player9 : Points=9 Name=FirstName9 LastName9 
Thread 28: 282 
+1

+1 - ¡Excelente primera pregunta! Bienvenido a StackOverflow! – jmort253

Respuesta

4

se JVM crear una nueva instancia del método estático y su local de variables en la Pila (excluyendo el objeto como estará en el Heap) para cada llamada por múltiples hilos?

Sí, eso es exactamente.

Si un método estático solo se refiere a las variables locales, es automáticamente seguro para subprocesos. (De hecho, esto también se aplica a los métodos no estáticos).

Hablando en general, diría que debe evitar static si es posible. En general, hace que el código sea más difícil de probar y razonar debido al hecho de que los miembros estáticos son, en cierto sentido, globales.

+0

métodos 'estáticos' son perfectamente buenos y razonables de usar. Por ejemplo 'Math.min'. Entonces son constantes como 'Math.PI'. Solo evite las variables 'estáticas' no finales, causan todo tipo de errores de multiproceso. –

+0

gracias por la respuesta muy rápida. eso es realmente lo que quiero lograr. Quiero que el método de ayuda actúe como un método global que cualquier hilo puede llamar en cualquier momento. mi diseño inicial en realidad fue el método está dentro de una clase normal y luego cada hilo creará una instancia de la clase y luego llamará al método. mi método estático real tiene mucha lógica dentro y me preocupa el rendimiento cada vez que creo una nueva instancia de él. pero como he demostrado anteriormente, el método no modificará el objeto que se le pasa. ¿Será mejor si continúo de esta manera, usando métodos estáticos? –

+0

@PopoyMakisig, esa es una pregunta realmente difícil de responder. Una vez escribí un juego con un 'Servidor 'de clase bastante central que tuve que pasar por todos lados para hacer cosas útiles aquí y allá. Me cansé y creé métodos estáticos. Al principio parecía una gran simplificación, pero al final lamenté la decisión y revirtí. Si yo fuera tú, lo probaría, vería cómo funcionó. Sé feliz con él si hace el trabajo, tómalo como una lección si terminas revirtiendo :-) – aioobe

4

static métodos no son un problema, solo static variables se compartirán entre subprocesos.

Así que dos hilos que invocan

public static int sum(int a, int b) { 
    int tmp = a + b; 
    return tmp; 
} 

no van a tener problemas.

static int tmp; 

public static int sum(int a, int b) { 
    tmp = a + b; 
    return tmp; 
} 

fallará multi-hilo, porque un hilo puede sobrescribir anothers tmp valor.

Las variables locales, incluso en los métodos static, son aún locales y por lo tanto seguros.

El uso de métodos static es bueno. Resalta que el método no requiere acceso a variables de objeto.Usar static variables no constantes es propenso a errores, evite esto a toda costa (y use la sincronización en una constante si necesita acceder a la variable).

+0

para el propósito de mi aplicación, no voy a usar variables estáticas no constantes. Estoy usando solo variables estáticas finales si necesito constantes definidas. entonces todo es sencillo en este momento. Usaré métodos de sincronización y/o instancia cuando la característica de concurrencia de Java ya sea muy clara para mí. gracias por su respuesta. –

+0

Acabas de salvar mi vida con esta frase: "Las variables locales, incluso en métodos estáticos, son aún locales y, por lo tanto, seguras". Estoy sorprendido con esta respuesta. Se siente intuitivamente mal, ¡pero menos mal que no! – aliteralmind

+0

Debería ser bastante obvio cuando uno ha trabajado con compiladores. Las variables locales se almacenan en la '' pila ''; y dado que cada hilo necesariamente tiene su propia pila, no pueden ver las variables locales de los demás. De hecho, se direccionan en relación con el puntero de la pila actual, por lo que también puede haber varias copias en la misma pila. De lo contrario, la recursión tampoco funcionaría correctamente. –

Cuestiones relacionadas