5. Definições (Meramente para este contexto)
Concorrência
Programas de rodam em paralelo compartilhando recursos de memória, io e
processamento.
Paralelismo
Programas que não compartilham memória, io e processamento.
Programação imperativa
Na Ciência da Computação, programação imperativa é um paradigma de
programação que descreve a computação como ações, enunciados ou
comandos que mudam o estado (variáveis) de um programa. Muito parecido
com o comportamento imperativo das linguagens naturais que expressam
ordens, programas imperativos são uma sequência de comandos para o
computador executar.
Programação funcional
Em ciência da computação, programação funcional é um paradigma de
programação que trata a computação como uma avaliação de funções
matemáticas e que evita estados ou dados mutáveis. Ela enfatiza a aplicação
de funções, em contraste da programação imperativa, que enfatiza mudanças
no estado do programa.
7. Starvation e Deadlocks
Locado Print Office
Executando
Find Game Games Add new Game
Kiosk Print Office
Locado Kiosk
Executando
Game
Take tickets Add tickets
8. Race Conditions
public class RaceCondition {
private static boolean done;
public static void main(final String[] args) throws InterruptedException {
new Thread(
new Runnable() {
public void run() {
int i = 0;
while(!done) { i++; }
System.out.println("Done!");
}
}
).start();
System.out.println("OS:" + System.getProperty("os.name"));
Thread.sleep(2000);
done = true;
System.out.println("flag done set to true");
}
}
9. Fixed Race Conditions
public class RaceCondition {
private static volatile boolean done;
public static void main(final String[] args) throws InterruptedException {
new Thread(
new Runnable() {
public void run() {
int i = 0;
while(!done) { i++; }
System.out.println("Done!");
}
}
).start();
System.out.println("OS:" + System.getProperty("os.name"));
Thread.sleep(2000);
done = true;
System.out.println("flag done set to true");
}
}
10. Fixed Race Conditions
Básicamente, volatile é usada para indicar que o valor da variável pode ser modificada por outras Threads.
Isso quer dizer que:
O valor da variável não será cacheado pela thread local, todas as leituras e escritas serão feitas na memória
principal
O acesso a variáveis age como se estivesse incluído em um bloco sincronizado.
11. Complexibilidade acidental sem limites
...
public class Account implements Comparable<Account> {
private int balance;
public final Lock monitor = new ReentrantLock();
public Account(final int initialBalance) { balance = initialBalance; }
public int compareTo(final Account other) {
return new Integer(hashCode()).compareTo(other.hashCode());
}
public void deposit(final int amount) {
monitor.lock();
try { if (amount > 0) balance += amount; } finally { monitor.unlock(); }
}
public boolean withdraw(final int amount) {
try {
monitor.lock();
if (amount > 0 && balance >= amount) {
balance -= amount;
return true;
}
return false;
} finally { monitor.unlock(); }
}
}
12. Fault tolerance
O que fazer quando acontece um erro dentro de um
conjunto de threads ou em uma thread que pertence a um
conjunto?
Escrever o código para esse tipo de tratamento e
complexo.
Talvez somente estamos adicionando mais
complexibilidade e novos pontos de falha do que
realmente tratando o problema.
14. Scale up / Scale out
Thread e um recurso muito caro, se vc quer atender muitos usuários.
public class DieLikeADog {
private static Object s = new Object();
private static int count = 0;
public static void main(String[] argv){
for(;;){
new Thread(new Runnable(){
public void run(){
synchronized(s){
count += 1;
System.err.println("New thread #"+count);
}
for(;;){
try {
Thread.sleep(1000);
} catch (Exception e){
System.err.println(e);
}
}
}
}).start();
}
}
}
23. Actors (Scala 2.10 unificará com implementação do akka 2.0)
import akka.actor.Actor
import akka.actor.Props
import akka.event.Logging
class MyActor extends Actor {
val log = Logging(context.system, this)
def receive = {
case "test" ⇒ log.info("received test")
case _ ⇒ log.info("received unknown message")
}
}
object Main extends App {
val system = ActorSystem("MySystem")
val myActor = system.actorOf(Props[MyActor], name = "myactor")
myActor ! “test”
}
24. Pattern Matching
object MatchTest1 extends Application {
def matchTest(x: Int): String = x match {
case 1 => "one"
case 2 => "two"
case _ => "many"
}
println(matchTest(3))
}
Nada impede o uso de estrategias antes ou depois do matching.
Eu prefiro depois.
25. Software Transactional Memory
Um STM transforma o heap do Java em uma base de dados transacional onde e possível iniciar
uma transacao begin/commit/rollback .
Muito parecido com banco de dados regulares.
Ela implementa as três primeiras letras contidas em ACID, ou seja
- Atomicidade
- Consistência
- Isolamento
26. Message passing approach
Actor message Address
Mailbox
Another Actor
Pode existir ou não.
Se não existir entra em ação
o sistema de tratamento de falhas
27. Fault Tolerance - “let it crash”
Exit signal
Sistema cai com um erro
28. Fault Tolerance com supervisores - “let it crash”
Exit signal
Supervisor
Supervsores identificam a falha e decidem por:
- Reiniciar o processamento
- Reiniciar o ator
- Reiniciar o sub-sistema.
30. Scale up / Scale out
Um MessageDispatcher Akka é o que faz os atores tão leves, este é o motor da
máquina por assim dizer.
Todas as implementações de MessageDispatcher são também um ExecutionContext, o
que significa que eles podem ser usados para executar código arbitrário.
Tenta tirar o melhor proveito possível do recurso Thread, usando adequadamente
Thread Pools.
Como os atores são isolados, fica fácil para subir novas instâncias em outras
máquinas e o serviço de endereçamento fica responsável pela entrega das
mensagens.
32. Real time applications com Play
def index = WebSocket.using[String] { request =>
// Just consume and ignore the input
val in = Iteratee.consume[String]()
// Send a single 'Hello!' message and close
val out = Enumerator("Hello!") >>> Enumerator.eof
(in, out)
}
Chamada simples
ws://localhost:9000/[controller].
33. Integração com Akka
val myActor = Akka.system.actorOf(Props[MyActor], name = "myactor")
Exemplo 1
def index = Action {
Async {
(myActor ? "hello").mapTo[String].asPromise.map { response =>
Ok(response)
}
}
}
Exemplo2
def index = Action {
Async {
Akka.future { longComputation() }.map { result =>
Ok("Got " + result)
}
}
}
Exemplo3
Akka.system.scheduler.schedule(0 seconds, 30 minutes, testActor, "tick")
Obs: cliente fica esperando, mas servidor pode receber nova conexao