Ci sono alcune cose da considerare. Se stai parlando di "Comunicare" all'interno di una singola applicazione, il solito percorso consiste nel creare una struttura di dati o oggetto che contenga i dati che vuoi comunicare e semplicemente assegnandoli alla classe / metodo che la userà.
È abbastanza comune voler condividere le informazioni tra diversi thread, nel qual caso tutti i thread devono avere accesso alla variabile in qualche modo e devi affrontare i problemi di concorrenza.
Le MOM di solito non funzionano a livello di processo interno, perché il passaggio di oggetti / dati è molto più conveniente quando si considera un solo processo. Una MOM semplificherà la comunicazione nel caso in cui le informazioni debbano essere condivise tra vari processi.
È un po 'come questo: tu ed io usiamo la stessa lingua. Se mi dici di andare a riempire la tua tazza di caffè, so come farlo. Potrei farlo a malincuore, ma so cosa fare. Questo tipo di comunicazione è ciò che hai all'interno del tuo processo: tutti si capiscono. Hai solo bisogno di capire come ottenere i dati giusti da un'entità all'altra.
Una MAM entra in gioco quando vuoi parlare con qualcuno che non ti capirà (un altro processo). C'è un sacco di lavoro che va nella trasmissione di informazioni. Si potrebbe pensare che sia semplice inviare un booleano o un array di numeri interi, ma può essere molto coinvolto. Cos'è un booleano? Un po? Un byte? Un numero intero? Cos'è un numero intero (per non parlare di un array intero)? Sono 8 bit, 16 bit, 32 bit, 64 bit? La MOM su un'estremità si occuperà fondamentalmente della seccatura di inviare un messaggio che dice "Sto inviando una matrice con 20 valori che sono numeri interi a 32 bit" seguiti da detto array. La MOM ricevente capisce il messaggio e può elaborarlo. Il motivo per cui non si utilizza una MOM all'interno di un processo è perché questi tipi di messaggi occupano più spazio di quanto sia necessario.
Se sono una subroutine e tu ne fai un'altra, tutto ciò che devo fare è scrivere la matrice in una locazione concordata in memoria (una variabile), e sarai in grado di vedere la matrice. Potremmo aver concordato in anticipo la dimensione dell'array (ovvero la pre-compilazione), ma anche in alcuni casi non è necessario comunicarlo. In questo caso stai utilizzando il linguaggio, la compilazione e il sistema di digitazione come MOM, perché sono queste le cose che danno significato a "L'array inizia all'indirizzo 0xDEADBEEF e utilizza 512 byte di memoria".
Ora, potrebbe usare ancora un MOM per inviare le cose all'interno dello stesso processo, puntando il mittente e il destinatario all'indirizzo di loopback, ma questo è un sovraccarico quando si passa semplicemente a variabili / parametri è quello che stai facendo davvero.
Modifica: un esempio concreto con Java
Per quanto riguarda le problematiche di accoppiamento di OP, vorrei presentare un esempio concreto di condivisione di messaggi in Java che ha un accoppiamento minimo tra i componenti. L'ho usato su diversi progetti ed è abbastanza semplice.
La base è usare un oggetto come BlockingQueue . Se non vuoi leggere la documentazione, il take-away è che questa è una coda sicura per i thread che consente a più thread di inserire elementi e portarli fuori senza che tu debba preoccuparti della concorrenza. Quindi ti ritroverai con qualcosa come BlockingQueue<Message>
. Il prossimo passo è ottenere questo oggetto nelle mani dei thread che lo useranno. Ciò significa che si passa il riferimento all'oggetto a ciascun thread o si può avvolgere la coda stessa in un singleton.
Una semplice implementazione in cui puoi passare il riferimento a un thread:
public class Producer implements Runnable {
BlockingQueue<Message> queue;
@Override
public void run() {
// TODO : Produce messages
}
public void initialize(BlockingQueue<Message> q) {
queue = q;
}
}
E il codice chiamante:
// Just a compile-able example of initializing such a queue:
BlockingQueue<Message> queue = new ArrayBlockingQueue<Message>(200);
// ...
Producer producer = new Producer();
producer.initialize(queue);
Thread t = new Thread(producer);
t.start();
I consumatori di questi messaggi apparirebbero molto simili. Ma puoi già vedere che diventa molto semplice creare più tipi di produttori (e consumatori), e tutti questi produttori / consumatori sono semplicemente accoppiati a una coda. Che si tratti di MockProducer
, DemoProducer
, RealProducer
, RealConsumer
, ecc., L'unico accoppiamento tra loro è la coda. La "comunicazione" tra produttori e consumatori è fondamentalmente se la coda è piena, vuota o da qualche parte nel mezzo. (E quello che faresti in ciascuno di questi stati è completamente un'altra discussione)
Naturalmente ci sono altre opzioni oltre alle code: puoi utilizzare qualsiasi struttura dati che desideri, con qualsiasi protocollo di messaggistica che puoi implementare. Devi solo preoccuparti della sicurezza del thread delle tue letture / scritture sulla struttura dei dati. Ho scelto la coda perché somiglia molto alla mia esperienza con la lettura / scrittura di una MAM - C'è un messaggio? Allora lo consumerò. Posso mettere qualcosa lì? Quindi produrrò un messaggio.