2012-04-04 8 views
11

Sto scrivendo un programma Java multithread in cui ogni thread potenzialmente ha bisogno del suo output standard reindirizzato su un file separato. Ogni thread avrebbe il proprio file. È possibile reindirizzare System.out su una base "per-thread" o sono le modifiche a System.out globale su tutti i thread?In un programma Java multithread, ogni thread ha la propria copia di System.out?

+0

Potrebbe essere possibile restituire un oggetto 'PrintStream' diverso utilizzando [AspectJ] (http://eclipse.org/aspectj) –

risposta

21

E 'possibile reindirizzare System.out su una base "per-thread"

No, non è possibile. System.out è statico e ce n'è uno per JVM che viene caricato come parte del classloader di sistema all'avvio iniziale di JVM. Anche se naturalmente si consiglia di utilizzare le chiamate di registrazione appropriate per thread, presumo che vi siano ragioni per le quali non è possibile farlo. Probabilmente una libreria di terze parti o altro codice è ciò che sta usando System.out in questo modo.

Una cosa che potresti fare (come suggerimento radicale) è creare il tuo PrintStream che delega a uno ThreadLocal<PrintStream>. Ma avrai bisogno di @Override tutti i metodi chiamati per farlo funzionare per-thread.

Infine, se ti stai chiedendo perché siete preoccupati per la concorrenza, System.out è un PrintStream quindi è già synchronized sotto le coperte e può essere utilizzato in modo sicuro da più thread.

+0

Attualmente sto esaminando il nome di ciascun thread e creando un PrintStream personalizzato che accetta una mappa . Quando il printstream personalizzato riceve un segnale per stampare qualcosa sullo schermo, utilizza Thread.currentThread per ottenere l'oggetto Thread corrente e lo cerca nella mappa. Se il thread è una chiave nella mappa, l'output viene scritto nel corrispondente OutputStream, altrimenti passa a un output predefinito. – user1258361

+1

È possibile utilizzare java.util.logging (o un altro framework di registrazione) con un formattatore appropriato per registrare il nome del thread. Consiglio vivamente questo approccio sull'uso di System.out. – Adamski

+0

Ho bisogno di reindirizzare l'output standard in una posizione variabile in base a quale thread è in esecuzione. I thread non generano messaggi di errore "log" standard. Ho esaminato Java Logging e non penso sia appropriato per il mio problema. – user1258361

3

System.out è statico e pertanto la stessa istanza è condivisa tra tutti i thread.

3

Hai ragione ma non nel modo in cui pensi. Quando un thread utilizza

System.out.println(); 

Prende una copia del riferimentoSystem.out, ma non una copia dell'oggetto questi riferimenti.

Ciò significa che normalmente tutti i thread vedranno lo stesso oggetto da scrivere in output.

Nota: questo campo non è sicuro per thread e se si chiama System.setOut(PrintStream) Se si utilizza questo, esiste una condizione di competizione indesiderata potenziale in cui thread diversi dispongono di copie locali diverse di System.out. Questo non può essere usato per risolvere questa domanda.

E 'possibile reindirizzare System.out su una base "per-thread"

È possibile farlo sostituendo System.out con una propria implementazione che è thread specifico. cioè una sottoclasse di PrintStream. Ho fatto questo per la registrazione in cui volevo che l'output di ciascun thread fosse coerente e non interlacciato. per esempio. Immagina di stampare due tracce di stack in due thread contemporaneamente. ;)

+1

Puoi controllarlo impostandolo prima di iniziare altri thread, altrimenti devi sperare che non importi. Cosa intendi per 'Boy questo è fuorviante? ' –

+0

C'è solo un singolo System.out. Quello che stai suggerendo è che tu cambi System.out a seconda del thread, che non è lo stesso di avere più System.out. Il tuo suggerimento è analogo a dire che avere 8 CD-ROM e una singola unità CD-ROM è equivalente ad avere 8 unità CD-ROM perché è possibile spegnere il CD quando necessario. I CD possono essere disattivati? Sì. È lo stesso di avere 8 unità CD? no. – user1258361

+0

Ti suggerisco di cambiare System.out per essere un componente che fa qualcosa di diverso su una base per thread. Questo non è lo stesso di avere più valori di System.out. Il mio commento riguardava la sicurezza del thread di System.out che consente a più thread di visualizzare valori diversi a causa di una condizione di competizione, qualcosa che non è possibile utilizzare e sarebbe solo un problema. Sto suggerendo di avere un caricatore CD da 8 che appare come una unità per l'utente, ad es. con 8 sottodirectory. –

5

E 'possibile reindirizzare System.out su una base "per-thread"

Alcuni sviluppatori da Maia Company hanno fornito una realizzazione pubblica di un PrintStream che fornisce un "STDOUT" per thread in questo articolo: "Thread Specific System.out".

Nella loro implementazione sovrascrivono solo metodi di scrittura, flush, close e checkError.Sembra essere abbastanza nel loro caso.

Essi no "necessità di @Override tutti i metodi chiamati a farlo funzionare per-filo" come @Gray affermato nella sua risposta.

+1

Sembra che questo collegamento sia morto, ma è possibile trovare un'implementazione simile in 'org.apache.geronimo.gshell.support.gshell-io.SystemOutputHijacker' [Pacchetto Maven] (https://mvnrepository.com/artifact/org .apache.geronimo.gshell.support/gshell-io/1.0-alpha-2) e [browser del codice sorgente] (http://grepcode.com/file/repo1.maven.org/maven2/org.apache.servicemix. kernel.gshell/org.apache.servicemix.kernel.gshell.core/1.1.0/org/apache/geronimo/gshell/IO/SystemOutputHijacker.java) –

0

E 'possibile reindirizzare System.out su una base "per-thread"

Li tutto possibile reindirizzare al delegato che sarà responsabile per la logica 'per-filo'.

Here is esempio di test parallelo di JBehave che hanno il proprio output di file.