2009-04-03 4 views
8

Donc, j'ai deux threads.Le thread PrintWriter d'une socket Java est-il sécurisé?

Le thread 1 gère les connexions client. (Il y a seulement un client et un serveur)
Je l'appelle mon thread de serveur.

Le thread 2 gère l'envoi de messages au client. Je l'appelle mon fil de processeur de message. Le thread un est responsable, entre autres d'envoyer un battement de coeur au client périodiquement. Lors de la programmation j'ai supposé que les sockets n'étaient pas thread-safe, mais les tampons étaient, et aussi longtemps que j'utilisais des tampons séparés pour les threads du serveur et du processeur, tout irait bien. J'ai également fait l'hypothèse que le "PrintWriter" était analogue au tampon socket en Java.

Dans ces hypothèses, j'ai écrit cette fonction pour envoyer un battement de coeur:

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'autre fil, celui de « processeur » fait quelque chose de similaire en ce qu'elle fait:

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

De cette manière Je créerais un nouveau "tampon" chaque fois que je souhaiterais envoyer un battement de coeur, et mes messages ne seraient jamais écrasés.

Malheureusement, cela ne semble pas être le cas. Et je reçois un message venant par le tuyau comme ceci: dsgdsbHEARTBEAT # sdg

Cela provoque une décharge de noyau plus tard.

Voici mes questions:

1) Sockets sont thread évidemment pas sûr, mais sont les PrintWriters que je reçois d'eux thread-safe? Ou est-ce juste de retourner le même PrintWriter?

2) Quelle est l'analogie avec le tampon socket de Java? Comment devrais-je penser à ce problème?

3) Comment faire en sorte que ces threads n'écrivent pas dans le même tampon sur le socket?

Répondre

10

C'est un mauvais design d'avoir ces multiples PrintWriter sur le même flux. Vraiment vous voulez au moins que l'objet les appelle à être synchronisé (ou thread confiné).

Cependant, en supposant pour une raison quelconque vous souhaitez que plusieurs PrintWriter s:

Premier problème: Writer s ne pas utiliser this comme la serrure. PrintWriter et BufferedWriter par défaut utilisent tous les deux le Writer ils sont construits avec comme le verrou. Ceci est évidemment complètement cassé. Ils devraient utiliser le verrou Writer, pas le Writer lui-même.Une erreur facile étant donné que le fait de verrouiller une fonctionnalité de Object supprime la sécurité de type statique. Vous aurez donc besoin de construire un PrintWriter avec le socket OutputStream (ou un autre objet commun) comme verrou.

Deuxièmement, nous avons la mise en mémoire tampon dans PrintWriter. Alors venez à la fin d'un tampon, la moitié s'écrit et la moitié attend la prochaine écriture. Pour éviter cela, vous pouvez soit verrouiller extérieurement pour associer print et flush, soit utiliser le rinçage automatique et ajouter un nouveau caractère de ligne. Donc, ce n'est pas de manière significative thread-safe, mais vous pouvez le pirater. Ou vous pouvez utiliser un meilleur design.

+0

J'ai jeté un oeil à Java SE 1.6.0_31 src pour cela. 'PrintWriter (Writer out)' appelle finalement 'Writer protégé (Object lock)' et là, 'Writer' assigne ce 'lock' à son 'lock' interne qui est utilisé dans 'Writer' pour la synchronisation. Alors pourriez-vous pl. expliquer pourquoi vous pensez que le verrouillage est cassé ici? – shrini1000

+0

@ shrini1000 'PrintWriter' appelle' Writer (Object lock) 'avec' super (out); '. Donc 'lock' est' out', au lieu de 'out.lock'. (Ceci est un problème d'implémentation - la spécification semble être manquante.) –

+0

Cela semble toujours être le cas dans Java 8 - Les appels PrintWriter super (out) et le verrou est sorti au lieu de out.lock. –

4

Vous avez besoin d'un moyen d'utiliser le même PrintWriter entre les threads (t1.writer == t2.writer, pas seulement PrintWriter s créés à partir de la même OutputStream). Avec le même PrintWriter, toutes les opérations d'écriture sont synchronisées.

+1

Vous dites que les PrintWriters sont thread-safe, mais que les OutputStreams ne le sont pas? – Alex

+3

Je pense que Chris dit que PrintWriter est thread-safe, mais deux sur le même flux ne sont pas significativement thread-safe. Par conséquent, utilisez-en un. –

Questions connexes