2009-04-03 21 views
8

Quindi, ho due thread.Il thread PrintWriter di un socket Java è sicuro?

Il primo thread gestisce le connessioni client. (C'è solo un client e un server)
Io lo chiamo thread del mio server.

Il thread due gestisce l'invio di messaggi al client. Lo chiamo thread del mio processore di messaggi.

Il thread uno è responsabile, tra l'altro, di inviare periodicamente un heartbeat al client.

Durante la programmazione ho ipotizzato che i socket non fossero thread-safe, ma i buffer lo erano, e fintanto che usavo buffer separati per i thread del server e del processore, andava bene.

Ho anche ipotizzato che "PrintWriter" fosse analogo al buffer di socket in Java.

Sotto queste ipotesi ho scritto questa funzione per inviare un battito cardiaco:

public void sendHeartBeat(){ 
     logger.info("Sending a hearbeat!"); 
     PrintWriter printWriter=null; 
     try { 
      printWriter = new PrintWriter(clientSocket.getOutputStream()); 
     } catch (IOException e) { 
      logger.info(e.toString()); 
     } 
     if(printWriter!=null){ 
      printWriter.print("HEARTBEAT#"); 
      printWriter.flush(); 
     } 
    } 

L'altro filo, quello "processor" fa qualcosa di simile a quello che fa:

printWriter=new PrintWriter(theServer.getClientSocket().getOutputStream()); 

In questo modo Creerei un nuovo "buffer" ogni volta che volevo inviare un heartbeat e i miei messaggi non sarebbero mai stati sovrascritti.

Sfortunatamente questo non sembra essere il caso. E ricevo un messaggio proveniente dalla pipe in questo modo: dsgdsbHEARTBEAT # sdg

Ciò causa un core dump in seguito.

Ecco le mie domande:

1) prese sono, ovviamente, non thread-safe, ma sono le PrintWriters che ricevo da loro thread-safe? O sta solo restituendo lo stesso PrintWriter?

2) Che cosa è analogo al buffer di socket in Java? Come dovrei pensare a questo problema?

3) Come faccio a fare in modo che questi thread non scrivano sullo stesso buffer sul socket?

risposta

10

È un design scarso avere questi multipli PrintWriter sullo stesso flusso. In realtà si desidera almeno l'oggetto che li chiama a essere sincronizzati (o thread confinati).

Tuttavia, supponendo che per qualche ragione si vuole più PrintWriter s:

Primo problema: Writer s non usano this come la serratura. PrintWriter e BufferedWriter di default usano entrambi il Writer con cui sono costruiti come il blocco. Questo è ovviamente completamente rotto. Dovrebbero utilizzare il lucchetto Writer e non lo stesso Writer.Un semplice errore dato che il blocco di una funzionalità di Object rimuove la sicurezza di tipo statico. Quindi è necessario costruire un PrintWriter con il socket OutputStream (o qualche altro oggetto comune) come blocco.

In secondo luogo, abbiamo il buffering entro PrintWriter. Quindi arriva la fine di un buffer, la metà viene scritta e metà aspetta la prossima scrittura. Per evitare ciò, bloccare esternamente per combinare uno print e flush, oppure utilizzare lo svuotamento automatico e aggiungere un nuovo carattere di linea.

Quindi, non è significativo thread-safe, ma è possibile modificarlo. Oppure puoi usare un design migliore.

+0

Ho dato un'occhiata a Java SE 1.6.0_31 src per questo. 'PrintWriter (Writer out)' in definitiva chiama 'Writer protetto (Object lock)' e lì 'Writer' assegna questo 'lock' al suo 'lock' interno che viene usato in 'Writer' per la sincronizzazione. Quindi potresti pl. spiega perché pensi che il blocco sia rotto qui? – shrini1000

+0

@ shrini1000 'PrintWriter' chiama' Writer (Object lock) 'con' super (out); '. Quindi 'lock' è' out', invece di 'out.lock'. (Questo è un problema di implementazione - la specifica sembra essere mancante.) –

+0

Questo sembra essere ancora il caso in Java 8 - PrintWriter chiama super (out) e lock è fuori invece di out.lock. –

4

È necessario un modo per utilizzare lo stesso PrintWriter tra i thread (t1.writer == t2.writer, non solo PrintWriter s creati dallo stesso OutputStream). Con lo stesso PrintWriter, tutte le operazioni di scrittura sono sincronizzate.

+1

Stai dicendo che i PrintWriter sono thread-safe, ma OutputStreams no? – Alex

+3

Penso che Chris abbia affermato che PrintWriter è thread-safe, ma due sullo stesso stream non sono significativamente thread-safe. Quindi usane uno. –