2012-04-13 3 views
5

Se ho questo codice sincronizzato che voglio sostituire con attori senza sincronizzazione, come?quale sarebbe il codice "attore" parallelo java per sostituire la sincronizzazione standard con i thread codice

public synchronized int incrementAndGet() { 
    i = i + 1; 
    return i; 
} 

e ho un gruppo di utenti in sito web in cui ho bisogno di tornare ciascuno un numero incrementale ... Come posso sostituire il codice con il codice di attori che non hanno sincronizzazioni in tal modo non hanno alcun codice di sincronizzazione di blocco. che immagino sarebbe quindi in grado di eseguirlo su multicores ecc. (non è questo lo scopo degli attori?).

+2

Questo è un caso perfetto per gli agenti Akka. – elbowich

risposta

3

Un semplice attore avvolgendo i nel suo stato interno:

case object Inc 

class IncrementingActor extends Actor { 
    var i = 0 

    protected def receive = { 
     case Inc => 
      i += 1 
      sender ! i 
    } 
} 

e bloccando l'uso (è necessario ottenere incrementAndGet in qualche modo):

import akka.pattern.ask 

def incrementAndGet() = 
    Await.result((incrementingActor ? Inc).mapTo[Int], 1 seconds) 

Questo codice è: lento, complicato e non idiomatico. Che mi dici di AtomicInteger?

+0

solo alcune domande sul codice sopra: – Jas

+0

non volevo usare atomicinteger, non volevo usare sincronizzato, internet è pieno di dire che gli attori possono sostituire il vecchio codice multithreaded con uno nuovo con attori senza sincronizzazione, quindi ho suggerito un esempio e vedo che mi dici che gli attori non risolvono il problema !!! Devo ancora fare Await.result o AtomicInteger che è proprio come scrivere sincronizzato !!! gli attori non risolvono il mio problema allora giusto !!? (nei miei esempi). (scusa se suono sconvolto la maggior parte dei tutorial dice che gli attori sono una soluzione magica al codice sincronizzato multithreading che non ho visto!) – Jas

+1

Il problema è che, con l'esempio che hai scelto, usare AtomicInteger è probabilmente la soluzione migliore. E anche AtomicInteger usa il confronto e lo scambio che è diverso da quello sincronizzato. –

3

La concorrenza è un vasto dominio con molteplici problemi e insidie. Non esiste un unico approccio in grado di risolvere tutti i problemi e un vero esperto di concorrenza è in grado di combinare diversi metodi per ottenere il miglior risultato.

Attualmente nel mondo JVM, non penso ci siano alternative migliori rispetto agli interi atomici per l'incremento di un contatore, specialmente se il conflitto è molto alto.

Detto questo, se si desidera utilizzare gli attori, il trucco per ottenere prestazioni e scalabilità è evitare chiedere le operazioni (?) il più possibile. Utilizzare dire invece (!) e quindi restituire. Quando il risultato è disponibile, l'attore lo riceverà e riprenderà il controllo. Nulla blocca e il pool di thread è in grado di occuparsi degli altri attori nel frattempo. Funziona solo se la maggior parte del codice è all'interno degli attori.

partire con la soluzione di Thomas, si può scrivere qualcosa di simile:

case object Inc 
case class Count(i) 

class IncrementingActor extends Actor { 
    var i = 0 
    protected def receive = { 
    case Inc => 
     i += 1 
     sender ! Count(i) 
    } 
} 

class FooActor(counter: ActorRef) extends Actor { 
    protected def receive = { 
    case DoSomething() => { 
     // Perform some work 
     counter ! Inc 
    } 
    case Count(i) => { 
     // Do something with the counter result 
    } 
    } 
} 
0

sincrono incrementare un contatore (come in incrementAndGet()) ha ben poco beneficio se si desidera utilizzare un attore. Nascosto dalla vista ci è la sincronizzazione effettivamente nella cassetta postale per l'attore. Inoltre, la classe AtomicInteger funziona perfettamente su architetture multicore.