Você está na página 1de 37

LABORATÓRIO DE

PROGRAMAÇÃO
AVANÇADA
Multithreading - Criação de Threads
Threads
¨ Thread é um processo leve e é
a unidade básica de utilização
da CPU
¨ É leve porque só tem
registradores e espaço de
pilha; o código, dados globais
e demais recursos, são
compartilhados
¨ Um processo pesado
(heavyweight) pode ter uma ou
mais threads (multithread)
¨ O compartilhamento faz com
que o overhead das threads
seja mínimo
Como criar threads em Java?
¨ Duas formas:
1) estender a classe Thread e
sobrescrevemos o seu método run() ou;
2) implementar uma classe a partir da
interface Runnable, escrevemos o método
run() e passamos essa classe ao construtor
da classe Threads
Exemplo 1
¨ No exemplo 1, vamos criar uma classe geral e que,
dentro dela, haverá uma classe interna (estática),
chamada Runner, que é a classe que implementa a
thread, estendendo a classe Thread e
sobrescrevendo o método run()
¨ A funcionalidade deste exemplo é que cada thread
imprima 5 vezes a string “Hello” + nome da thread,
com um intervalo de 500 ms entre cada
¨ Interno à classe principal (dentro do método main)
serão gerados duas threads (mas pode-se gerar
muito mais do que isso)
Exemplo 1
:: Estendendo a classe Thread

public class App {


static class Runner extends Thread {
public void run() {
. . .
}
}
public static void main(String[] args) {
Runner runner1 = new Runner();
runner1.start();
Runner runner2 = new Runner();
runner2.start();
}
}
Exemplo 1
:: Estendendo a classe Thread
Expandindo a classe Runner

public class App {


static class Runner extends Thread {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("Hello: " + i + " Thread: " +
Thread.currentThread().getName());
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
}
}
}
public static void main(String[] args) {
. . .
}
}
Exemplo 1
:: Estendendo a classe Thread

Hello: 0 Thread: Thread-0 A mudança entre os nomes das threads


Hello: 0 Thread: Thread-1 é por causa do intercalamento das
Hello: 1 Thread: Thread-0 execuções das threads
Hello: 1 Thread: Thread-1
Hello: 2 Thread: Thread-1
Hello: 2 Thread: Thread-0
Hello: 3 Thread: Thread-0
Hello: 3 Thread: Thread-1
Hello: 4 Thread: Thread-1
Hello: 4 Thread: Thread-0

IMPORTANTE: As threads são unidades “independentes”. Nunca pense que as


várias threads serão executadas de forma rigorosamente sequencial
Exemplo 2
¨ No exemplo 2, vamos criar uma classe externa,
chamada Runner, que é a classe que implementa a
thread, que também vai estender a classe
Thread e sobrescrever o método run()
¨ Também será criado uma classe principal, que vai
instanciar duas threads (mas poderia ter muito
mais), isto é, dois objetos da classe Runner
¨ O objetivo deste exemplo é exatamente o mesmo
que o exemplo 1
Exemplo 2
:: Estendendo a classe Thread

class Runner extends Thread {


public void run() {
. . .
}
}

public class App2 {


public static void main(String[] args) {
Runner runner1 = new Runner();
runner1.start();
Runner runner2 = new Runner();
runner2.start();
}
}
Exemplo 2
:: Estendendo a classe Thread
Expandindo a classe Runner
class Runner extends Thread {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("Hello: " + i + " Thread: " +
Thread.currentThread().getName());
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
}
}
}
public class App2 {
public static void main(String[] args) {
. . .
}
}
Exemplo 2
:: Estendendo a classe Thread

Hello: 0 Thread: Thread-0


Hello: 0 Thread: Thread-1
Hello: 1 Thread: Thread-0
Hello: 1 Thread: Thread-1
Hello: 2 Thread: Thread-0
Hello: 2 Thread: Thread-1
Hello: 3 Thread: Thread-0
Hello: 3 Thread: Thread-1
Hello: 4 Thread: Thread-1
Hello: 4 Thread: Thread-0

IMPORTANTE: As threads são unidades “independentes”. Nunca pense que as


várias threads serão executadas de forma rigorosamente sequencial
Exemplo 3
¨ No exemplo 3, vamos criar uma classe externa,
chamada RunnerRunnable, que é a classe que
implementa a thread, que vai implementar a
interface Runnable e sobrescrever o método
run() e passar essa classe ao construtor da classe
Threads
¨ Também será criado uma classe principal, que vai
instanciar duas threads (mas poderia ter muito
mais), isto é, dois objetos da classe RunnerRunnable
¨ O objetivo deste exemplo é exatamente o mesmo
que os exemplos 1 e 2
Exemplo 3
:: Implementando a interface Runnable

class RunnerRunnable implements Runnable {


public void run() {
. . .
}
}

public class App3 {


public static void main(String[] args) {
Thread thread1 = new Thread(new RunnerRunnable());
Thread thread1 = new Thread(new RunnerRunnable());
thread1.start();
thread2.start();
}
}
Exemplo 3
:: Implementando a interface Runnable
Expandindo a classe RunnerRunnable
class RunnerRunnable implements Runnable {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("Hello: " + i + " Thread: " +
Thread.currentThread().getName());
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
}
}
}
public class App3 {
public static void main(String[] args) {
...
}
}
Exemplo 3
:: Implementando a interface Runnable

Hello: 0 Thread: Thread-1


Hello: 0 Thread: Thread-0
Hello: 1 Thread: Thread-0
Hello: 1 Thread: Thread-1
Hello: 2 Thread: Thread-0
Hello: 2 Thread: Thread-1
Hello: 3 Thread: Thread-0
Hello: 3 Thread: Thread-1
Hello: 4 Thread: Thread-0
Hello: 4 Thread: Thread-1

IMPORTANTE: As threads são unidades “independentes”. Nunca pense que as


várias threads serão executadas de forma rigorosamente sequencial
Exemplo 4
¨ No exemplo 4, vamos criar uma classe geral e que,
dentro dela, haverá uma classe interna (estática),
chamada RunnerRunnable, que é a classe que
implementa a thread, que também vai implementar a
interface Runnable, sobrescrever o método run()
e passar essa classe ao construtor da classe Threads
¨ Interno à classe principal (dentro do método main)
serão gerados duas threads (mas pode-se gerar muito
mais do que isso)
¨ O objetivo deste exemplo é exatamente o mesmo dos
exemplos 1, 2 e 3
Exemplo 4
:: Implementando a interface Runnable

public class App4 {


static class RunnerRunnable implements Runnable {
public void run() {
. . .
}
}

public static void main(String[] args) {


Thread thread1 = new Thread(new RunnerRunnable());
Thread thread1 = new Thread(new RunnerRunnable());
thread1.start();
thread2.start();
}
}
Exemplo 4
:: Implementando a interface Runnable
Expandindo a classe RunnerRunnable
public class App4 {
static class RunnerRunnable implements Runnable {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("Hello: " + i + " Thread: " +
Thread.currentThread().getName());
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
}
}
}
public static void main(String[] args) {
. . .
}
}
Exemplo 4
:: Implementando a interface Runnable

Hello: 0 Thread: Thread-0


Hello: 0 Thread: Thread-1
Hello: 1 Thread: Thread-0
Hello: 1 Thread: Thread-1
Hello: 2 Thread: Thread-1
Hello: 2 Thread: Thread-0
Hello: 3 Thread: Thread-0
Hello: 3 Thread: Thread-1
Hello: 4 Thread: Thread-1
Hello: 4 Thread: Thread-0

IMPORTANTE: As threads são unidades “independentes”. Nunca pense que as


várias threads serão executadas de forma rigorosamente sequencial
Exemplo 5
¨ No exemplo 5, vamos criar uma classe geral e que,
dentro dela, haverá duas classes internas (estática),
uma implementando estendendo a classe Thread e a
outra implementando a interface Runnable
¨ Interno à classe principal (dentro do método main)
serão gerados duas threads (mas pode-se gerar muito
mais do que isso)
¨ O objetivo de cada thread é imprimir três vezes (com
um intervalo de tempo aleatório) a mensagem “Usando
Heranca” + nome da thread ou “Usando Runnable” +
nome da thread, conforme for o caso
Exemplo 5
:: As duas formas de implementação na mesma classe
import java.util.Random;
public class App5 {
static class Task1 extends Thread {
public void run() { ... }
}
static class Task2 implements Runnable {
public void run() { ... }
}
public static void main(String[] args) {
Task1 threadComHeranca1 = new Task1();
Task1 threadComHeranca2 = new Task1();
Thread threadComRunnable1 = new Thread(new Task2());
Thread threadComRunnable2 = new Thread(new Task2());
threadComHeranca1.start();
threadComHeranca2.start();
threadComRunnable1.start();
threadComRunnable2.start();
}
}
Exemplo 5
:: As duas formas de implementação na mesma classe

Expandindo a classe Task1


public class App5 {
static class Task1 extends Thread {
public void run() {
Random r = new Random();
for(int i=0; i<3; i++) {
System.out.println("Usando Heranca " +
Thread.currentThread().getName());
try {
Thread.sleep(r.nextInt(500));
} catch (InterruptedException e) {}
}
}
}
static class Task2 implements Runnable {...}
public static void main(String[] args) {...}
}
Exemplo 5
:: As duas formas de implementação na mesma classe

Expandindo a classe Task2


public class App5 {
static class Task1 extends Thread {...}
static class Task2 implements Runnable {
public void run() {
for(int i=0; i<3; i++) {
Random r = new Random();
System.out.println("Usando Runnable " +
Thread.currentThread().getName());
try {
Thread.sleep(r.nextInt(500));
} catch (InterruptedException e) {}
}
}
}
public static void main(String[] args) {..}
Exemplo 5
:: As duas formas de implementação na mesma classe

Usando Runnable Thread-3


Usando Heranca Thread-0
Usando Heranca Thread-1
Usando Runnable Thread-2
Usando Runnable Thread-3
Usando Heranca Thread-1
Usando Runnable Thread-3
Usando Heranca Thread-0
Usando Heranca Thread-0
Usando Runnable Thread-2
Usando Runnable Thread-2
Usando Heranca Thread-1

IMPORTANTE: As threads são unidades “independentes”. Nunca pense que as


várias threads serão executadas de forma rigorosamente sequencial
Exemplo 6
:: Threads anônimas (Runnable)
¨ No exemplo 6, vamos apresentar o conceito de thread
anônima, que significa que você não precisa definir
uma classe para uma thread
¨ Neste exemplo, implementa a interface Runnable
¨ É utilizada em casos bastante específicos onde você
não vai utilizar esta thread em lugar algum
¨ A funcionalidade desta thread anônima será imprimir
cinco vezes (com um intervalo de 100ms) a mensagem
“Hello” + valor do contador + “Thread” + identificador
da thread
Exemplo 6
:: Threads anônimas (Runnable)
public class App6 {
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("Hello: " + i + " Thread: " +
Thread.currentThread().getId());
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {}
}
}
});
thread1.start();
}
}
Exemplo 6
:: Threads anônimas (Runnable)

Hello: 0 Thread: 9
Hello: 1 Thread: 9
Hello: 2 Thread: 9
Hello: 3 Thread: 9
Hello: 4 Thread: 9
Exemplo 7
:: Threads anônimas (Thread)
¨ No exemplo 7, vamos reapresentar o conceito de
thread anônima, dessa vez estendendo a classe Thread
¨ Relembrando que este conceito é utilizada em casos
bastante específicos onde você não vai reutilizar esta
thread em lugar algum
¨ Da mesma forma que o exemplo anterior, a
funcionalidade desta thread anônima será imprimir
cinco vezes (com um intervalo de 100ms) a mensagem
“Hello” + valor do contador + “Thread” + identificador
da thread
Exemplo 7
:: Threads anônimas (Thread)

public class App9 {


public static void main(String[] arg) {
new Thread() {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("Hello: " + i + " Thread: " +
Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) { }
}
}
}.start();
}
}
Exemplo 7
:: Threads anônimas (Thread)

Hello: 0 Thread: 9
Hello: 1 Thread: 9
Hello: 2 Thread: 9
Hello: 3 Thread: 9
Hello: 4 Thread: 9
Exemplo 8
¨ No exemplo 8, vamos mostrar que uma thread pode
receber parâmetros. Serão definidas quatro threds
¨ Este exemplo estende a classe Thread
¨ A funcionalidade de cada thread será receber um
parâmetro numérico (value). Internamente, cada thread
executará um loop na variável i, de 0 até 19, e
imprimirá uma mensagem contendo o nome da thread
se i for divisível por value
Exemplo 8
:: Threads com parâmetros
class RunnerArg extends Thread {
private int value;
public RunnerArg (int val) {
this.value = val;
}
public void run() {
for (int i = 0; i < 20; i++) {
if (i%value==0) {
System.out.println(Thread.currentThread().getName() +
": " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
}
}
}
Exemplo 8
:: Threads com parâmetros

public class App7 {


public static void main(String[] args) {
RunnerArg runner[] = new RunnerArg [4];
for (int i=0; i<4; i++) {
runner[i] = new RunnerArg(i+3);
runner[i].start();
}
}
}
Exemplo 8
:: Threads com parâmetros
Thread-0: 0
Thread-1: 0
Thread-2: 0
Thread-3: 0
Thread-0: 3
Thread-0 (3): Thread-3: 6
0, 3, 6, 9, 12, 15, 18 Thread-2: 5
Thread-1 (4): Thread-1: 4
0, 4, 8, 12, 16 Thread-0: 6
Thread-2 (5): Thread-3: 12
0, 5, 10, 15 Thread-2: 10
Thread-3 (6): Thread-1: 8
0, 6, 12, 18 Thread-3: 18
Thread-0: 9
Thread-1: 12
Thread-2: 15
Thread-0: 12
Thread-1: 16
Thread-0: 15
Thread-0: 18
Qual a melhor?
¨ Depende
¨ Estender Thread é mais simples; implementar
Runnable é mais flexível
¨ Se você não precisar herdar de mais de uma classe
eu estenderia Thread porque fornece alguns
métodos embutidos, como yield(), interrupt(), e
outros, que não estão disponíveis na interface
Runnable
Referências
¨ https://docs.oracle.com/javase/8/docs/api/java/l
ang/Thread.html
¨ https://docs.oracle.com/javase/8/docs/api/java/l
ang/Runnable.html
¨ https://javapapers.com/core-java/why-multiple-
inheritance-is-not-supported-in-java/
Fim

Você também pode gostar