Implementazione della comunicazione tra pacchetti (Java)

7

Sto facendo un progetto con 5 pacchetti. I pacchetti possono comunicare tra loro inviando messaggi a MessageQueue centrale nel pacchetto principale e MessageQueue si occupa di tutti i messaggi. (cfr .: link )

Fornita questa immagine:

ipacchettisarebberoiclient(siapublisherchesottoscrittori)eMessageQueuesarebbel'argomento.

OrastoimplementandoMessageQueue(a.k.a.ilTopicnell'immaginesopra)eipacchettipossonogiàiscriversiaMessageseipacchettipossonoanchepubblicareunmessaggio.
Pubblicareunmessaggioèsoloaggiungereilmessaggioaunacoda"dentro" il MessageQueue.

Quindi in un dato momento durante l'esecuzione ci possono essere 0, 1 o più messaggi nel MessageQueue e ora devo assicurarmi che MessageQueue elabori tutti questi messaggi correttamente (e in ordine).

Un modo per farlo potrebbe essere il seguente:

public class MessageQueue {

    public MessageQueue(){
        //initialising etc.
        processMessages();
    }

    private void processMessages(){
        while(/*program is running*/){
            if(queue.isNotEmpty()){
                /*process first message in queue*/
            }
        }
   }

Tuttavia, credo che questo non sia un ottimo design e talvolta viene definito busy waiting ?

Come potrei approcciarlo in un modo migliore (senza usare alcuno standard API ofcourse)?

    
posta Aerus 22.04.2011 - 17:10
fonte

2 risposte

5

Come hai detto, stai facendo una lunga attesa qui. Devi rendere il blocco del thread finché la coda dei messaggi non diventa vuota.

I primitivi per farlo sono i metodi wait e notify della classe Object . Usare correttamente questi primitivi può essere complicato, anche quando si ha una buona conoscenza del multithreading. Fondamentalmente, wait crea un blocco di thread e notify invia un segnale al thread in attesa.

Uno strumento più di alto livello (che è certamente basato su wait e notify ) sono le classi del pacchetto java.util.concurrent.locks . Principalmente, Lock e Condition . Un Condition ha metodi simili a wait e notify .

Un altro strumento che puoi utilizzare è un BlockingQueue . Quando viene richiesto di fornire un oggetto, una coda di blocco bloccherà il thread corrente fino a quando non diventa vuoto. Sotto il cofano, usa le stesse primitive wait / notify descritte sopra. È una soluzione valida per il tuo problema specifico.

Una soluzione di livello superiore, che ti astrae dal thread in esecuzione, consiste nell'utilizzare un ExecutorService . ExecutorService.newSingleThreadExecutor() farebbe il trucco. Invia solo Runnable oggetti a ExecutorService e li eseguirà in modo asincrono in un thread dedicato.

Puoi scegliere una di queste soluzioni per implementare il tuo sistema di messaggistica. Dipende solo dalla quantità di controllo che vuoi o dal livello che stai cercando di padroneggiare (se lo fai per imparare la programmazione).

    
risposta data 22.04.2011 - 18:20
fonte
3

La tua domanda è davvero poco chiara. Perché stai provando a implementare il tuo middleware personale invece di utilizzare un'implementazione JMS disponibile come quella di ActiveMQ? È estremamente difficile implementare qualcosa di solido come framework ampiamente disponibili.

La maggior parte delle implementazioni fornisce sia messaggi sincroni (bloccanti) che asincroni (con callback). Così alleggerendo la necessità di aspettare molto tempo.

Se ti stai chiedendo cosa succede sotto il cofano - la maggior parte delle implementazioni JMS sono multithreaded. Quindi c'è un thread (eseguito dal framework) che riceve i messaggi, e c'è il thread dell'utente che attende il messaggio. In una situazione di lettura di messaggi bloccanti, il thread dell'utente chiama l'operazione "richiama messaggio" e, se uno non è presente, blocca in attesa su un monitor. Quando arriva un messaggio, il thread di gestione dei messaggi del framework "notifica" il monitor, che quindi riattiva il thread dell'utente per recuperare il messaggio. L'infrastruttura di threading di Java è costruita esattamente per questo, per evitare l'attesa di attività visibile all'utente.

È un buon esercizio implementarlo personalmente (spesso definito produttore-consumatore), ma la robustezza è spesso PITA, quindi ancora una volta, le strutture esistenti sono la soluzione migliore.

BTW: ho spesso usato JMS tra pacchetti sullo stesso computer e spesso la stessa JVM. È abbastanza efficiente e facile da ridimensionare. Sono disposto a scommettere che sotto il cofano la struttura calcola che è in esecuzione sulla stessa JVM e utilizza uno spazio condiviso in memoria. Quando passi a macchine su computer diversi, il tuo codice utente non cambia, solo la tua latenza.

    
risposta data 22.04.2011 - 17:20
fonte

Leggi altre domande sui tag