JAVA MULTITHREADING TECHNIQUES PROGRAMAÇÃO PARALELA ÚLTIMA PARTE
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); }