setlayout definicion create java multithreading synchronization locking

java - definicion - setlayout jpanel



¿Cómo asegurar que `methodB` está" bloqueado "si algunos hilos están en` methodA` en Java? (5)

Class clazz tiene dos métodos methodA() y methodB() .

¿Cómo asegurar que el methodB está "bloqueado" si algunos hilos están en el methodA en Java (estoy usando Java 8)?

Al "bloquear el método B", quiero decir que "espere a que no haya hilos en el método A ()". (Gracias a @AndyTurner)

Tenga en cuenta que el requisito anterior permite las siguientes situaciones:

  1. Múltiples hilos se encuentran simultáneamente en el methodA
  2. Múltiples hilos están en el methodB mientras que no hay hilos en el methodA
  3. Los methodB en el methodB no impiden que otros subprocesos ingresen el methodA

Mi prueba: uso StampedLock lock = new StampedLock .

  • En el methodA A, llame a long stamp = lock.readLock()
  • Crea un nuevo método para unlockB y llama a lock.unlockRead(stamp) en él.
  • En el methodB , llame a long stamp = lock.writeLock() y lock.unlockWrite(stamp) .

Sin embargo, esta estrategia de bloqueo no permite la segunda y la tercera situaciones anteriores.

Editar: me doy cuenta de que no he especificado claramente los requisitos de la sincronización entre el methodA y el methodB El enfoque dado por @JaroslawPawlak funciona para el requisito actual (lo acepto), pero no para mi intención original (tal vez debería aclararlo primero y luego publicarlo en otro hilo).


¿Por qué no usar un tipo de orquestador externo? Me refiero a otra clase que será responsable de llamar al método A o al método B cuando lo permita. El hilo múltiple aún se puede manipular mediante bloqueo o tal vez solo con algunos AtomicBoolean (s).

A continuación, encontrará un borrador ingenuo de cómo hacerlo.

public class MyOrchestrator { @Autowired private ClassWithMethods classWithMethods; private AtomicBoolean aBoolean = = new AtomicBoolean(true); public Object callTheDesiredMethodIfPossible(Method method, Object... params) { if(aBoolean.compareAndSet(true, false)) { return method.invoke(classWithMethods, params); aBoolean.set(true); } if ("methodA".equals(method.getName())) { return method.invoke(classWithMethods, params); } } }


Creo que esto puede hacer el truco:

private final Lock lock = new ReentrantLock(); private final Semaphore semaphore = new Semaphore(1); private int threadsInA = 0; public void methodA() { lock.lock(); threadsInA++; semaphore.tryAcquire(); lock.unlock(); // your code lock.lock(); threadsInA--; if (threadsInA == 0) { semaphore.release(); } lock.unlock(); } public void methodB() throws InterruptedException { semaphore.acquire(); semaphore.release(); // your code }

Los hilos que ingresan al methodA aumentan el conteo e intentan obtener un permiso del semáforo (es decir, toman 1 permiso si está disponible, pero si no están disponibles, simplemente continúan sin un permiso). Cuando el último hilo abandona el methodA , se devuelve el permiso. No podemos usar AtomicInteger ya que cambiar el recuento y el permiso de adquisición / liberación del semáforo debe ser atómico.

Los hilos que ingresan al methodB necesitan tener un permiso (y esperarán uno si no está disponible), pero después de que lo obtienen lo devuelven inmediatamente permitiendo que otros hilos ingresen al methodB

EDITAR:

Otra versión más simple:

private final int MAX_THREADS = 1_000; private final Semaphore semaphore = new Semaphore(MAX_THREADS); public void methodA() throws InterruptedException { semaphore.acquire(); // your code semaphore.release(); } public void methodB() throws InterruptedException { semaphore.acquire(MAX_THREADS); semaphore.release(MAX_THREADS); // your code }

Cada hilo en el methodA tiene un único permiso que se libera cuando el hilo abandona el methodA

Los hilos que entran en el methodB esperan hasta que estén disponibles los 1000 permisos (es decir, no hay hilos en el methodA ), pero no los mantienen, lo que permite que otros hilos entren en ambos métodos mientras que el método methodB todavía se está ejecutando.


En términos muy simples, lo que todos necesitan es ENTER methodB only if no thread inside methodA .

  • Simplemente puede tener un contador global, inicializado primero en 0 para registrar la cantidad de hilos que se encuentran actualmente en el methodA() . Debería tener un lock/mutex asignado para proteger el count variables.
  • Los hilos que entran en los métodos A count++ .
  • Los hilos que salen del método A count-- .
  • Los hilos que ingresan al método B primero deben verificar si el count == 0 .

    methodA(){ mutex.lock(); count++; mutex.signal(); //do stuff mutex.lock(); count--; mutex.signal(); } methodB(){ mutex.lock(); if(count != 0){ mutex.signal(); return; } mutex.signal(); //do stuff }


Necesitaría un int para contar los hilos en el método A, y ReentrantLock.Condition para señalar todos los hilos esperando en el método B una vez que no haya subprocesos en el método A:

AtomicInteger threadsInMethodA = new AtomicInteger(0); Lock threadsForMethodBLock = new ReentrantLock(); Condition signalWaitingThreadsForMethodB = threadsForMethodBLock.newCondition(); public void methodA() { threadsInMethodA.incrementAndGet(); //do stuff if (threadsInMethodA.decrementAndGet() == 0) { try { threadsForMethodBLock.lock(); signalWaitingThreadsForMethodB.signalAll(); } finally { threadsForMethodBLock.unlock(); } } } public void methodB() { try { threadsForMethodBLock.lock(); while (!Thread.isInterrupted() && threadsInMethodA.get() != 0) { try { signalWaitingThreadsForMethodB.await(); } catch (InterruptedException e) { Thread.interrupt(); throw new RuntimeException("Not sure if you should continue doing stuff in case of interruption"); } } signalWaitingThreadsForMethodB.signalAll(); } finally { threadsForMethodBLock.unlock(); } //do stuff }

Por lo tanto, cada subproceso que ingrese el método B primero verificará si hay nadie en el método A, y señalará los hilos de espera anteriores. Por otro lado, cada subproceso que ingrese el método A incrementará el contador para evitar que los nuevos subprocesos funcionen en el método B, y al decrementar liberará todos los subprocesos que esperan hacer cosas en el método B si no quedan subprocesos dentro del método A.


Realmente no se puede evitar que se llame a ese método o métodoB (mientras que otros subprocesos están dentro del otro método), pero puede implementar la intercomunicación de subprocesos de tal manera que aún pueda lograr lo que desea.

class MutualEx { boolean lock = false; public synchronized void methodA() { if (lock) { try { wait(); }catch (InterruptedException e) { } } //do some processing lock = true; notifyAll(); } public synchronized void methodB() { if (!lock) { try { wait(); }catch (InterruptedException e) { } } //do some processing lock = false; notifyAll(); } }

Ahora, para que esto funcione, cualquier objeto Thread creado debe tener una referencia a la misma instancia de objeto MutualEx.