Tengo un problema cuando se utiliza el mismo método por 2 hilos .
El problema es: Parece que cuando un hilo llamado método, y el método se está ejecutando, y en el mismo tiempo que otro hilo intenta llamar al mismo método, Java simplemente omitir esa llamada ! Por lo tanto, cuando 2 hilos están pidiendo el mismo método, ese método se llama sólo una vez. Por lo tanto, a veces al azar Programm se omita método y código no se ejecuta en absoluto! ¿Como es posible? Intentado en diferentes máquinas, definitivamente no funciona como se esperaba y me parece un error tremendo de Java.
Por favor, si cualquier experto leerá esto, se puede describir lo que sucede y si es problema conocido, dame el enlace a la explicación. ¡Gracias!
PD: El código está en pleno funcionamiento, sólo puede pegar incluso a java en línea como repl.it o similar. Justo después de a.updateCounter (inc); Puedo comprobar si incrementador trabajó (línea 45).
class Main {
public static void main(String[] args) {
ThreadOne t1 = new ThreadOne(1000, 300, "Thread 1");
ThreadOne t2 = new ThreadOne(1, 300, "Thread 2");
Thread one = new Thread(t1);
Thread two = new Thread(t2);
one.start();
two.start();
}
}
class Accum {
private static Accum a = new Accum();
private int counter = 0;
private Accum() {}
public static Accum getAccum() {
return a;
}
public void updateCounter(int add) {
counter += add;
}
public int getCount() {
return counter;
}
}
class ThreadOne implements Runnable {
Accum a = Accum.getAccum();
int inc;
int max;
String threadName;
ThreadOne(int i, int c, String name) {
inc = i;
max = c;
threadName = name;
}
public void run() {
for(int x = 0; x < max; x++) {
int check = a.getCount();
a.updateCounter(inc);
if(check + inc != a.getCount()) System.out.println("\nupdateCounter was skipped at x " + x + "\nThread name: " + threadName);
try {
Thread.sleep(5);
} catch(InterruptedException ex) {
System.out.println("x: " + x + "\n ex: " + ex);
}
}
System.out.println(threadName + ": " + a.getCount());
}
}
En primer lugar, Java no se salta la llamada. Es sólo el resultado real que no coincide con su prueba.
Entre int check = a.getCount();
y la prueba if(check + inc != a.getCount())
, el contador se cambia simplemente por el otro hilo . Eso es tan simple como eso.
UPDATE: La operación counter += add
no es ATOMIC , es decir, puede visualizarla como una secuencia de 3 operaciones:
- El valor de
counter
que se lee - Un nuevo valor se calcula
- Este nuevo valor se asigna a
counter
Ahora imagine 2 hilos que realizan esta secuencia exactamente en el mismo tiempo, y se entiende por qué el valor no consigue incrementa.
Solución para hacer esta llamada atómica: Simplemente utilizar AtomicInteger
según lo mencionado por @gudok:
import java.util.concurrent.atomic.AtomicInteger;
public class Accum {
private static Accum a = new Accum();
private AtomicInteger counter = new AtomicInteger(0);
private Accum() {}
public static Accum getAccum() {
return a;
}
public void updateCounter(int add) {
counter.addAndGet(add);
}
public int getCount() {
return counter.intValue();
}
}