JAVA MULTITHREADING TECHNIQUES PROGRAMAÇÃO PARALELA ÚLTIMA PARTE

Preview:

Citation preview

JAVA MULTITHREADINGTECHNIQUES

PROGRAMAÇÃO PARALELA ÚLTIMA PARTE

PRIMEIRA LINGUAGEM DE PROGRAMAÇÃO A DISPONIBILIZAR PRIMITIVAS DE CONCORRÊNCIA:

LINGUAGEM ADA (Departamento de Defesa do USA)

Pouco difundida e utilizada nas Universidades e Empresas

JAVA : É A ÚNICA LING DE USO GERAL E POPULAR QUE TORNOU AS PRIMITIVAS DE CONCORRÊNCIA DISPONÍVEIS PARA PROGRAMADORES DE APLICATIVOS.

C, C++, DELPHI : SÃO CHAMADAS LINGUAGENS DE UMA ÚNICA THREAD. FAZEM CHAMADAS A PRIMITIVAS DE MULTITHREADING DO SISTEMA OPERACIONAL

CLASSE THREAD (PACOTE: JAVA.LANG)

VÁRIOS CONSTRUTORES:

public Thread ( String threadnome), constrói um objeto Thread cujo nome é threadnome.

public Thread(), constrói um Thread cujo nome é:

Thread-(1, 2, 3, ... )

VÁRIOS MÉTODOS:RUN ( O CÓDIGO DA THREAD PROPRIAMENTE DITO É

SOBRESCRITO NESSE MÉTODO)

START (DISPARA UMA THREAD CHAMANDO O

MÉTODO RUN E RETORNA PARA O SEU CHAMADOR IMEDIATAMENTE)

OUTROS MÉTODOS:

INTERRUPT,

ISALIVE,

YIELD,

SETNAME,

GETNAME

POR QUE JAVA ? ? ?POR QUE JAVA ? ? ?

ORIENTADAORIENTADA A OBJETOS A OBJETOS

PORTABILIDADEPORTABILIDADE

LIVRELIVRE

API API RIQUÍSSIMARIQUÍSSIMA: : BDBD, , I/OI/O, , REDESREDES, ETC., ETC.

VASTÍSSIMA VASTÍSSIMA DOCUMENTAÇÃODOCUMENTAÇÃO

SOLUÇÃO JAVA PARA PORTABILIDADESOLUÇÃO JAVA PARA PORTABILIDADE

PROGRAMA FONTE

(.JAVA)

JAVAC

EXECUTAVEL

JVM (.CLASS)

SOLARIS

LINUX

WINDOWS

IBM , XPTO

INDEPENDENTE PLATAFORMA

DEPENDENTE PLATAFORMA

CRIANDO UMA THREAD:

•EXTENDS THREADEXTENDS THREAD

•IMPLEMENTS RUNNABLEIMPLEMENTS RUNNABLE

package java.lang;public interface Runnable {            public abstract void run();}

class TpThread extends Thread {private int t;

public TpThread (int thr){

t = (int) (Math.random()* 5000 );System.out.println("A Thread:"+thr+"dormirá:"+t);

}public void run(){

try{ sleep ( t ); System.out.println("Thread:"+thr+ "acordando");} catch (InterruptedException erro ){

System.out.println( erro);}

}}

public class TestaThreads

{

public static void main ( String args[])

{

TpThread t1, t2, t3, t4;

t1 = new TpThread ( 1 );

t2 = new TpThread ( 2 );

t3 = new TpThread ( 3 );

t4 = new TpThread ( 4 );

System.out.println( " \nStartando as Threads" );

t1.start();

t2.start();

t3.start();

t4.start();

System.out.println( " \nThreads Startadas\n" );

}

}

class TpThreadRun implements Runnable

{

private int t;

public TpThreadRun (int th)

{

t = (int) (Math.random() * 5000 );

System.out.println(" Tempo para : "+th+” “+ t );

}

public void run()

{

try

{

sleep ( t );

}

catch (InterruptedException erro )

{

System.out.println( erro);

}

System.out.println(" Thread:”+th+” acordando");

}

}

public class Testa

{

public static void main ( String args[])

{

TpThreadRun t1, t2, t3, t4;

Thread th1, th2, th3, th4;

t1 = new TpThreadRun();

t2 = new TpThreadRun();

t3 = new TpThreadRun();

t4 = new TpThreadRun();

th1 = new Thread ( t1 );

th2 = new Thread ( t2 );

th3 = new Thread ( t3 );

th4 = new Thread ( t4 );

System.out.println( " \nStartando as Threads" );

th1.start();

th2.start();

th3.start();

th4.start();

System.out.println( " \nThreads Startadas\n" );

}

}

CICLO DE VIDA DE UMA THREAD

NASCIMENTO

PRONTO

RODANDO

ESPERANDO

DORMINDOMORTO

BLOQUEADO

NOTIFY OU

NOTIFYALL

TEMPO FIM

CONCLUSÃO DO I/O

DESPACHA

QUANTUM FIM

WAIT

SLEEP

INICIO DO I/O

COMPLETO

START

Th01 blockedTh01 compete com

outras blockedsno mesmo obj

Th01 calls um metodosynchronized Th01 exec metodos antes

do wait ()

Th01 exec metodos apos wait ()

Th01 compete com thspelo lock

Th01 blocked

Th01 no conjuntodas wait

Th01 compete noconj. wait

start

Lock ganho por outra thX

Th01 tenta novamente

Th01 não obtem lock do obj

Th01 é selecinado para ter o lock

Th01 chama wait()

ThX call notify()

Th01 não é o escolhido

Th01 é o escolhido

Th01 requer lock do objTh01 não consegue

Th01 obtem lock do obj

Th01 termina deixa o obj.

DADOSX, Y, Z

PROC P

PROC Q

PROC R

COND C1

COND C2

SINALIZADOR

P1

P9

P7

P2

P3P4

P6P5MONITOR de HOAREMONITOR de HOARE wait( c1 )

signal (c1)

DADOSX, Y, Z

SYNCHRONIZED P

SYNCHRONIZED Q

SYNCHRONIZED R

WAIT( )

P1P9

P7

P2

P3P4

P6

P5MONITOR em MONITOR em JAVAJAVA

Notify( )

thread

thread

thread

thread

objeto

objeto

objeto

monitor

monitor

monitormonitor

public class Cabine{

private int ncab;public Cabine ( int n ){

ncab = n;}

public synchronized void Pega(){ try {

while ( ncab == 0 ) wait();ncab--;

} catch ( Exception e ){}}public synchronized void Larga(){

ncab++;notify();

}}

public class Cesto{

private int ncesto;public Cesto ( int n ){

ncesto = n;}public synchronized void Pega(){ try {

while ( ncesto == 0 ) wait();ncesto--;

} catch (Exception e ){}}

public synchronized void Larga(){

ncesto++;notify();

}}

public class Nadador extends Thread {

String nome;Cesto cesto;Cabine cabine;int n;public Nadador ( int n, Cesto cesto, Cabine cabine ){

this.n = n;this.cesto = cesto;this.cabine = cabine;

}public void run(){ try {

cesto.Pega();cabine.Pega();System.out.println("..... "+ n +“ RETIRANDO A ROUPA");sleep ( (int) ( Math.random() * 5000 ));cabine.Larga();System.out.println(“..."+ n +“ NADANDO ");sleep ( (int) ( Math.random() * 5000 ));cabine.Pega();System.out.println("....."+ n +" COLOCANDO A ROUPA");sleep ( (int) ( Math.random() * 5000 ));cabine.Larga();cesto.Larga();

} catch ( Exception e ) {}}

}

public class Main {

public static void main ( String args[]){

Cabine cab;Cesto cesto;Nadador nadador[];

cab = new Cabine( 4 );

cesto = new Cesto ( 7 );

nadador = new Nadador[ 20 ];

for ( int i = 0; i <= 19; i++ ){ nadador[i]= new Nadador(i,cesto,cab); nadador[i].start();}

} }

IMPLEMENTAÇÃO IMPLEMENTAÇÃO DE ARQUIVOS DE ARQUIVOS

DESCRITORDESCRITOR DE ARQUIVO:DE ARQUIVO:

É UMA ESTRUTURA ( UM É UMA ESTRUTURA ( UM REGISTRO ) QUE CONTÉM TODAS REGISTRO ) QUE CONTÉM TODAS AS INFORMAÇÕES SOBRE O AS INFORMAÇÕES SOBRE O ARQUIVO.ARQUIVO.

DESCRITOR DE UM DESCRITOR DE UM ARQUIVO:ARQUIVO:

ATRIBUTOS ATRIBUTOS

++ LOCALIZAÇÃO DO LOCALIZAÇÃO DO ARQUIVO EM DISCO ARQUIVO EM DISCO

ARQ / DESCR

MEMORIA

OPENOPEN

CLOSECLOSE

UNIX / LINUX O DESCR. ARQ UNIX / LINUX O DESCR. ARQ >>>>>>>>>> INODEINODE

TDAATDAAOS SISTEMAS DE ARQUIVOS, OS SISTEMAS DE ARQUIVOS, NORMALMENTE, MANTÉM, NA NORMALMENTE, MANTÉM, NA MEMÓRIA, UMA TABELA DE MEMÓRIA, UMA TABELA DE REGISTROS DESCRITORES DE REGISTROS DESCRITORES DE TODOS OS ARQUIVOS ABERTOS.TODOS OS ARQUIVOS ABERTOS.

DESCR. ARQ1

NUM. PROC. UTILIZANDO

DESCR. ARQ3

NUM. PROC. UTILIZANDO

DESCR. ARQ 5

NUM. PROC. UTILIZANDO

DESCR. ARQ 9

NUM. PROC. UTILIZANDO

TDAATDAA

ABERTURA DE UM ARQUIVO POR UM PROCESSO:

OPEN ( ARQ, RO )OPEN ( ARQ, RO )

ENTRE TANTAS ENTRE TANTAS MARAVILHAS MARAVILHAS DO UNIX: DO UNIX:

TODOS OS TODOS OS DISPOSITIVOS DISPOSITIVOS DE I /ODE I /O SÃO SÃO TRATADOS TRATADOS COMO COMO ARQUIVOSARQUIVOS. .

IMPRESSORA IMPRESSORA

VIDEO VIDEO

TECLADO

TODOS SÃO CONSIDERADOS E TODOS SÃO CONSIDERADOS E

TRATADOS COMO TRATADOS COMO ARQUIVOSARQUIVOS

A ENTRADA 00 É O ARQUIVO DE ENTRADA PADRÃO, RO

TECLADOTECLADO

A ENTRADA 11 É O ARQUIVO DE SAÍDA PADRÃO, W

VÍDEOVÍDEO

READ ( X, Y, Z ) ;READ ( X, Y, Z ) ;

READ ( 0, X, Y, Z ) ;READ ( 0, X, Y, Z ) ;

WRITE ( A, B, C ) ;WRITE ( A, B, C ) ;

WRITE ( 1, A, B, C ) ;WRITE ( 1, A, B, C ) ;

NOME DO ARQUIVO 1NOME DO ARQUIVO 1 NUM. DO INODENUM. DO INODE

NOME DO ARQUIVO ...NOME DO ARQUIVO ... NUM. DO INODENUM. DO INODE

NOME DO ARQUIVO 2NOME DO ARQUIVO 2 NUM. DO INODENUM. DO INODE

NOME DO ARQUIVO 3NOME DO ARQUIVO 3 NUM. DO INODENUM. DO INODE

NOME DO ARQUIVO NNOME DO ARQUIVO N NUM. DO INODENUM. DO INODE

UM DIRETÓRIO DE UMA UM DIRETÓRIO DE UMA PARTIÇÃO LINUXPARTIÇÃO LINUX

REGISTRO DESCRITOR DE ARQUIVO INODE

DONO

ETC ...

DATA

PERMISSÃO

01

910

12

DADOS

DADOS

...........

DADOS

10 BLOCOS DE 4 KBYTES CADA

DADOS

DADOS

...........

DADOS

BLOCO COM 1024 APONTADORES

1024 BLOCOS COM 4 KB

DOS E WINDOWS

DATA, DONO, ...NOME ........................ 9

8

LIVRE

EOF0

7

RUIM

EOF

421

0

1

2

3

4

5

6

7

89

IMPLEMENTAÇÃO IMPLEMENTAÇÃO DE ARQUIVOS EM DE ARQUIVOS EM

JAVAJAVADESCRITOR DE ARQUIVO:DESCRITOR DE ARQUIVO:

É UM OBJETO QUE CONTÉM É UM OBJETO QUE CONTÉM TODAS AS INFORMAÇÕES SOBRE TODAS AS INFORMAÇÕES SOBRE O ARQUIVO.O ARQUIVO.

JAVA ENXERGA UM ARQUIVO COMO SENDO UM FLUXO SEQUENCIAL DE BYTES. UM STREAM DE BYTES.

UM DESCRITOR DE ARQUIVO EM JAVA PASSA A SER UM OBJETO DE FLUXO.

TRES OBJETOS DE FLUXOS SÃO CRIADOS AUTOMATICAMENTE QUANDO SE INICIA A EXECUÇÃO DE UM PROGRAM EM JAVA:

System.in

System.out

System.err

•BYTES STREAM

•CHARACTER STREAM (UNICODE 16 BITS)

CLASSES ABSTRATAS PARA BYTES STREAM:

InputStreamOutputStream

CLASSES ABSTRATAS PARA CHARACTER STREAM:

READERWRITER

ARQUIVO

MEMÓRIA

REDE

TECLADO ETC . . .

FONTE

PROGRAMA

STREAM CHARACTERS UNICODE 16 BITS

BufferReader

CharArrayReader

InputStreamReader

FilterReader

PipedReader

StringReader

Super Classe

Reader

ARQUIVO

MEMÓRIA

REDE

VÍDEO

ETC . . .

DESTINO

PROGRAMA

STREAM CHARACTERS UNICODE 16 BITS

BufferWriter

CharArrayWriter

FilterWriter

PipedWriter Super ClasseWriter

ARQUIVO

MEMÓRIA

REDE

TECLADO ETC . . .

FONTE

PROGRAMA

STREAM BYTES 8 BITS

BufferedInputStream

DataInputStream

FilterInputStream

ObjectInputStream

PipedInputStream

StringBufferInputStream

Super ClasseInputStream

ARQUIVO

MEMÓRIA

REDE

VÍDEO ETC . . .

DESTINO

PROGRAMA

STREAM BYTES 8 BITS

BufferOutputStream

DataOutputStream

FilterOutputStreamPipedOutputStream Super

ClasseOutputStream

import java.io.*;public class Main{ public static void main(String[] args){ echo ( System.in ); } public static void echo(InputStream instream){ int i; try { while (true) { i = instream.read(); if ( i == -1 ) break; // observe que sem o “cast” um caracter "A", por exemplo,

// seria escrito como "65" char c = (char) i;

System.out.print( c ); } } catch (IOException e) { System.err.println(e); } }}

import java.io.*;class FileOutputDemo{

public static void main (String args[] ){FileOutputStream out; PrintStream p; try{

// Cria um novo file output stream // conecta ao arquivo chamado "arq.txt"

out = new FileOutputStream ( "arq.txt");

// conecta o print stream ao output stream

p = new PrintStream ( out );

for ( int i = 0; i <= 20; i++ )p.println (" jdfgfdgdfhlkjasdhflksdfds "+i);

p.close(); } catch (Exception e ) { System.err.println( e ); }

}}

Filtros StreamsAs classes java.io.FilterInputStream e java.io.FilterOutputStream são subclasses concretas de InputStream e OutputStream que de algum modo modificam dados lidos (escritos) de um stream básico. Raramente essas classes são diretamente utilizadas. Porém, suas subclasses são extremamente importantes, especialmente as classes DataInputStream e DataOutputStream. Um filtro stream é conectado a um stream básico quando o stream original é passado ao construtor do stream filtro.

Por exemplo: Para criar um novo DataOutputStream de um FileOutputStream pode se fazer: FileOutputStream fos = new FileOutputStream( "arq.txt" );DataOutputStream dos = new DataOutputStream( fos );

É muito comum em Java a prática de se combinar filtros na forma:DataOutputStream dos = new DataOutputStream ( new FileOutputStream( " arq.txt" ) );

import java.io.*;class FileInputDemo{

public static void main (String args[] ){FileInputStream arq; DataInputStream in; try{

// Abre um arquivo existente chamado "arq.txt“

arq = new FileInputStream ( "arq.txt");

// CONVERTE o arquivo inputstream em um // datainputstream

in = new DataInputStream ( arq );

while ( in.available() != 0 )System.out.println( in.readLine() );

in.close();}catch (IOException e ) { System.err.println( e); }

}}

Os pipes são canais de comunicação sincronizados entre threads. Um pipe é estabelecido entre dois threads: um thread envia dados para outro gravando em um PipedOutputStream (uma subclasse de Outputstream). O thread destino lê as informações do pipe via um PipedInputStream (uma subclasse de InputStream). Vejam os exemplos:

PIPESPIPES

import java.io.*;public class ThrFonte extends Thread {

Writer pipe; String linha;public ThrFonte ( Writer p ){

pipe = p;}public void run() {

try{BufferedWriter out = new BufferedWriter ( pipe );DataInputStream teclado =

new DataInputStream ( System.in );  for ( int i = 0; i < 10; i++ ){

linha = teclado.readLine();out.write( linha );

out.newLine(); }out.flush(); out.close();

}catch ( IOException erro ) { System.err.println( erro ); }

}}

import java.io.*;

public class ThrDestino extends Thread {

Reader pipe;

String linha;

public ThrDestino ( Reader p ){

pipe = p;

}

public void run() {

try{

BufferedReader in = new BufferedReader ( pipe );

while ( ( linha = in.readLine() ) != null )

System.out.println ( "Leu a linha: "+ linha );

}

catch ( IOException erro ) { System.err.println( erro ); }

}

}

 

 

import java.io.*;

public class MainPipe{

public static void main (String args[] ) {

ThrDestino destino;

ThrFonte fonte;

try{

PipedWriter pontaEscreve = new PipedWriter();

PipedReader pontaLe =

new PipedReader ( pontaEscreve );

destino = new ThrDestino ( pontaLe );

fonte = new ThrFonte ( pontaEscreve );

destino.start();

fonte.start();

}

catch ( IOException e ) { System.out.println( e ); }

}

}

import java.io.*;

public class ObjMsg implements Serializable {

int n;

public ObjMsg ( int n ) {

this.n = n;

}

public void escreva() {

for ( int i = 1; i <= n; i++ )

System.out.println("Mensagem do ObjMsg : "+ i );

}

}

import java.io.*;

public class Thrfonte extends Thread {

OutputStream pipe;

OutputStream saida; // destino

ObjMsg objmsg; String linha;

public Thrfonte ( OutputStream p , ObjMsg obms){

pipe = p;

objmsg = obms;

}

public void run(){

try {

ObjectOutputStream saida =

new ObjectOutputStream ( pipe );

saida.writeObject ( objmsg );

saida.flush();

saida.close();

}

catch ( Exception e ) {}

}

}

import java.io.*;

public class Thrdestino extends Thread {

InputStream pipe;

InputStream entrada; // fonte

ObjMsg objMsg;

public Thrdestino ( InputStream p ) {

pipe = p;

}

public void run() {

try {

ObjectInputStream entrada = new ObjectInputStream ( pipe );

objMsg = (ObjMsg) entrada.readObject();

}

catch ( Exception e ) {}

objMsg.escreva();

}

}

import java.io.*;

public class Main {

public static void main ( String [] args ) {

Thrfonte fonte;

Thrdestino destino;

ObjMsg objmsg;

try {

PipedOutputStream pontaEscreve =

new PipedOutputStream();

PipedInputStream pontaLe =

new PipedInputStream( pontaEscreve );

objmsg = new ObjMsg( 20 );

fonte = new Thrfonte ( pontaEscreve , objmsg );

destino = new Thrdestino ( pontaLe );

destino.start();

fonte.start();

}

catch ( Exception e ) {}

}

}

SOCKETSSOCKETS  Um Socket é a representação Java de uma conexão de Rede TCP. Utilizando a classe Socket, um cliente pode estabelecer um canal de comunicação, baseado em streams, com um host remoto.

Para se comunicar com um host remoto usando o protocolo TCP/IP, o cliente deve inicialmente criar um Socket para o host remoto. Isso, automaticamente, estabelece uma conexão TCP. Devem ser especificados o nome do host e a porta TCP a ser utilizada, ou seja, um inteiro entre 1 a 65.535.

Uma vez estando o Socket criado, os seus métodos getInputStream() e getOutputStream() podem ser utilizados para se obter streams através do qual o cliente pode se comunicar com o servidor.

 

A classe ServerSocket é o mecanismo através do qual um servidor pode aceitar conexão de clientes através da rede. O procedimento básico para implementar um servidor é abrir um ServerSocket em uma particular porta local e então esperar pela conexão proveniente de um cliente. Clientes irão se conectar a aquela porta e assim a conexão se estabelecerá. As portas de 1 a 1023 são reservadas para os serviços do Sistema e assim somente podem ser utilizados pelos SU’s.

A classe ServerSocket cria um Socket para cada conexão de cliente. O servidor extrai esses Sockets invocando o método accept() do ServerSocket, e então, manipula esses sockets de maneira usual, tipicamente extraindo um InputStream e um OutputStream e comunicando se com o cliente através da interface padrão de streams.

 

RESUMINDO, PARA SE ESTABELENCER UM SERVIDOR SIMPLES EXECUTAMOS 5 PASSOS:

I 1. criando um objeto ServerSocket:

ServerSocket ss = new ServerSocket ( porta, fila);

 2. conectando a um cliente através do método accept de ServerSocket. Cada conexão de cliente é gerenciada por um objeto Socket.

Socket conexão = ss.accept();

Quando uma conexão é estabelecida um objeto Socket retorna e é referenciado por conexão.

 

1.

 .3. obtendo os objetos OutputStream e InputStream que iram permitir que o servidor comunique-se com o cliente. O servidor envia as informações para o cliente via um objeto OutputStream. O servidor recebe as informações do cliente via um objeto InputStream. Para obter os fluxos, o servidor invoca o método getOutputStream do Socket para obter uma referência ao OutputStream associado com o socket. Invoca o método getInputStream do Socket para obter uma referência ao objeto InputStream associado com o socket.

Se for necessário enviar ou receber valores de dados primitivos (como int e double, etc) ou tipos de classe (como String, Employee) em vez de enviar e receber bytes, pode-se encadear outros tipos de fluxo (como ObjectOutputStream e ObjectInputStream) ao OutputStream e ao InputStream associados com o socket.

Exemplo:Exemplo:

ObjectInputStream entrada = ObjectInputStream entrada =

new ObjectInputStream (conexão.getInputStream() );new ObjectInputStream (conexão.getInputStream() );

  

ObjectOutputStream saida = ObjectOutputStream saida =

new ObjectOutputStream (conexão.getOutputStream() );new ObjectOutputStream (conexão.getOutputStream() );

  

Estabelecendo esse relacionamento, tudo o que o Estabelecendo esse relacionamento, tudo o que o servidor escrever no servidor escrever no ObjectOutputStreamObjectOutputStream é enviado via é enviado via OutputStreamOutputStream e fica disponível no e fica disponível no InputStreamInputStream do cliente do cliente e vice versa.e vice versa.

. 4. servidor e cliente comunicando via objetos InputStream e OutputStream:

  msg = (String) entrada.readObject();

  saida.writeObject ( msg );

saida.flush();

 

5.   fechando a conexão:

 

conexão.close(); 

 

NO LADO DO CLIENTE 3 PASSOS SÃO SUFICIENTES:

 

1.     Abrindo um socket

  Socket csock = new Socket ( “nome da maquina”, porta );

  

2.     Criando um fluxo de entrada e um de saída

 

Pode ser utilizada a classe DataInputStream para criar um fluxo de entrada para receber respostas do servidor:

  DataInputStream entrada;

try{

entrada = new DataInputStream ( csock.getInputStream() );

}

catch (IOException e ) { System.out.println(e) ; }

Como já visto a classe DataInputString permite que sejam lidas linhas de texto e tipos primitivos de dados do JAVA de uma maneira portável. Essa classe possui métodos como read, readChar, readInt, readDouble e readLine.

 

Da mesma maneira um fluxo de saída, para o cliente enviar informações ao socket do servidor, pode ser criado utilizando a classe PrintStream ou DataOutputStream do Java.io .

 

DataOutputStream saida;

Try{

saida = new PrintStream ( csock.getOutputStream());

} catch (IOException e ) { System.out.println(e); }

Poderia também ser utilizada a classe DataOutputStream para criar um fluxo de saída para o cliente:

 DataOutputStream saida;

Try{

saida = new DataOutputStream( csock.getOutputStream() );

} catch (IOException e ) { System.out.println(e);}

  

 

3.   Fechando o socket.

 

É sempre importante fechar os fluxos de entrada e de saída antes de fechar o socket:

 

Try{

saida.close();

entrada.close();

csock.close();

} catch (IOException e ) { System.out.println(e); }

Recommended