en tratar de mejorar mi comprensión de los problemas de concurrencia, estoy mirando el escenario siguiente (Editar: he cambiado el ejemplo de la Lista de tiempo de ejecución, que está más cerca de lo que estoy tratando):¿Determinar el alcance de sincronización?
public class Example {
private final Object lock = new Object();
private final Runtime runtime = Runtime.getRuntime();
public void add(Object o) {
synchronized (lock) { runtime.exec(program + " -add "+o); }
}
public Object[] getAll() {
synchronized (lock) { return runtime.exec(program + " -list "); }
}
public void remove(Object o) {
synchronized (lock) { runtime.exec(program + " -remove "+o); }
}
}
Tal como está, cada método es seguro mediante subprocesos cuando se usa de forma independiente. Ahora, lo que estoy tratando de averiguar es cómo manejar donde la clase que llama desee llamar:
for (Object o : example.getAll()) {
// problems if multiple threads perform this operation concurrently
example.remove(b);
}
Pero como se ha señalado, no hay ninguna garantía de que el Estado va a ser consistente entre la llamada a getAll() y las llamadas a eliminar(). Si hay varios hilos que llaman a esto, tendré problemas. Entonces mi pregunta es: ¿Cómo debo habilitar al desarrollador para que realice la operación de manera segura? Idealmente, deseo aplicar la seguridad del hilo de una manera que dificulte que el desarrollador evite/omita, pero al mismo tiempo no es complicado de lograr. Puedo pensar en tres opciones hasta ahora:
A: Haga que el bloqueo sea 'esto', de modo que el código de llamada acceda al objeto de sincronización, que luego puede envolver los bloques de código. Desventaja: Es difícil de cumplir en tiempo de compilación:
synchronized (example) {
for (Object o : example.getAll()) {
example.remove(b);
}
}
B: Coloque el código combinado en la clase Ejemplo - y beneficiarse de la posibilidad de optimizar la aplicación, como en este caso. Desventaja: Dolor para agregar extensiones, y el potencial de mezcla lógica no relacionada:
public class Example {
...
public void removeAll() {
synchronized (lock) { Runtime.exec(program + " -clear"); }
}
}
C: proporcionar una clase de cierre. Desventaja: El exceso de código, potencialmente demasiado generoso de un bloque de sincronización, de hecho, podría hacer más fácil los puntos muertos:
public interface ExampleClosure {
public void execute(Example example);
}
public Class Example {
...
public void execute(ExampleClosure closure) {
synchronized (this) { closure.execute(this); }
}
}
example.execute(new ExampleClosure() {
public void execute(Example example) {
for (Object o : example.getAll()) {
example.remove(b);
}
}
}
);
¿Hay algo que me falta? ¿Cómo se debe sincronizar la sincronización para garantizar que el código sea seguro para subprocesos?
Disculpe, el ejemplo no estaba claro. He eliminado la referencia a la Lista. Solo estoy tratando de encontrar la mejor manera de lidiar con: Blah result = example.method1(); example.method2 (resultado); donde la llamada al método2 puede causar problemas porque entre el método1 y el método2, otro subproceso fue llamado método3(). – Mike