Autore Topic: [medio] Introduzione ai Thread  (Letto 17514 volte)

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
[medio] Introduzione ai Thread
« il: 05 Marzo 2011, 12:24:55 CET »
+8
Introduzione ai THREAD
Questo è un tutorial introduttivo ai Thread rivolto a chi ha pochissima o nessuna conoscenza sull'argomento. Non è il tutorial definitivo e neanche quello perfetto, tutti sono i benvenuti nel contribuire a renderlo migliore e più completo. Il codice degli esempi sarebbe da sistemare un po', ma meglio postare qualcosa di imperfetto, che niente.

Livello di difficoltà: medio
Versione SDK utilizzata: almeno 1.5
Sorgenti: vedi file in allegato

Una delle caratteristiche che sono state date ad Android per funzionare su sistemi relativamente limitati come gli smartphone, senza comprometterne l'usabilità e la velocità di risposta, è la maggiore importanza data all'interfaccia utente. Lavorando con il vostro computer, vi sarà sicuramente accaduto che un'applicazione impegnata in attività più o meno onerose, non reagisca ai comandi dell'utente e addirittura la sua interfaccia risulti bloccata. Su Android questo comportamento non è permesso a livello di sistema. Viene quindi richiesto allo sviluppatore un diverso approccio di base: eseguire le operazioni pesanti in un thread separato. 

Un Thread è una parte di codice la cui esecuzione è indipendente da altri Thread. Può essere pensato come un piccolo programma a sé stante, che inizia e finisce per conto suo, che comunica con altri Thread e scambia dati. I thread creati nell'ambito della stessa applicazione si dice che appartengono allo stesso processo e condividono l'accesso alla stessa memoria. Un'applicazione si dice multi-threaded se è composta da più Thread.


Il modello di threading di Android

La più semplice applicazione HelloWorld per Android crea un solo thread, quello principale (main), che è sempre il thread dell'interfaccia utente (UI). Questo thread si occupa dell'interazione con l'utente attraverso l'interfaccia grafica. Come detto sopra, il sistema operativo Android richiede che il thread della UI sia sempre pronto a rispondere all'interazione, e se rimane impegnato in una attività per oltre 5 secondi, l'applicazione viene automaticamente chiusa (Application Not Responding - Force Close).

L'implementazione pratica di un thread può essere fatta: estendendo la classe Thread (il metodo più semplice, ma meno flessibile), usando dei Runnable (più generale perchè astrae il codice dal thread vero e proprio nel quale sarà eseguito) o un AsyncTask (ancora più ad alto livello perchè gestisce in automatico un thread pool e l'interazione il thread di UI).

Creare e far partire un thread parallelo (il nostro si chiamerà WorkerThread) risolve il problema del carico sul main thread della UI, ma una volta che la sua esecuzione indipendente è partita, sorge il problema di farlo comunicare con il thread della UI (che è l'unico abilitato ad accedere ed aggiornare l'interfaccia grafica). Per assolvere questo compito, il sistema ci mette a disposizione i messaggi e le funzioni per scambiarli in modo affidabile e consistente tra thread distinti.

In questo primo esempio vedremo come creare un Thread e come comunicare con il thread di UI tramite messaggi.


Implementazione di un Thread

Dobbiamo creare una classe WorkerThread come estensione di Thread. La variabile membro mCallerHandler manterrà una copia locale del destinatario dei messaggi ed il suo valore sarà impostato nel costruttore al momento che il Main Thread instanzierà il WorkerThread.

Codice (Java): [Seleziona]
class WorkerThread extends Thread {  
   public Handler mCallerHandler;
   private int nn = 1;

   public WorkerThread(Handler handler) {
      mCallerHandler = handler;
      Log.i(TAG,"WorkerThread creato");
   }

Realizziamo il metodo per richiedere l'avvio del thread (attenzione, si parla di richiesta perchè al ritorno della funzione non è detto sia stato già fatto). E' consigliabile non terminare esplicitamente il thread, ma lasciare che il thread esca naturalmente a seguito della fine del codice da eseguire.

Codice (Java): [Seleziona]
      public void start() {
         running = true;
         super.start();
         Log.i(TAG,"richiesto avvio WorkerThread");
      }

Il codice utente che dovrà essere eseguito dal WorkerThread è contenuto nel metodo run(). Questo metodo da solo non fa niente, è l'entry point del thread, cioè il metodo che sarà eseguito a partire dalla chiamata del metodo start(). Fintanto che viene eseguito codice, il thread è da considerarsi vivo (alive), non appena il metodo run() viene terminato, il thread è da considerarsi morto (dead). Un thread morto non può essere riavviato, ne deve essere creata una nuova istanza.

Per operazioni una tantum, va benissimo il thread che parte e muore. Altre volte ci interesserà che rimanga in vita ed esegua continuamente certe operazioni. In questo primo esempio vediamo il primo caso.

Codice (Java): [Seleziona]
public void run() {
   try {
      Log.i(TAG,"WorkerThread inizia qua");
      // codice utente qua
      Log.i(TAG,"WorkerThread finisce qua");
      }
   } catch (InterruptedException e) {
      Log.e(TAG,"errore in WorkerThread "+e.toString());
   }
}

Per inviare un messaggio al thread della UI utilizziamo il metodo di mCallerHandler che ci permette di ottenere un oggetto messagio, riempirlo con i nostri valori e poi spedirlo all'Handler. Ci sono varie modalità per passare parametri e dati (due sono mostrati qua sotto), si faccia riferimento all'help di obtainMessage per dettagli sull'utilizzo.

Codice (Java): [Seleziona]
int nn = 0;
mCallerHandler.obtainMessage(MSG_A,nn,-1).sendToTarget();

String tmsg = "Testo";
byte[]tbuf = tmsg.getBytes();
mCallerHandler.obtainMessage(MSG_B,tbuf.length,-1,tbuf).sendToTarget();
 

Uso dei Thread

Torniamo nel thread principale della nostra UI. Inseriamo due Button, uno per creare e avviare il thread e uno per fermarlo (che non useremo in questo primo esempio, ma ci servirà nei prossimi). Sotto inseriamo una TextView adibita a logging degli eventi su schermo.

Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <TextView
                android:layout_width="fill_parent"
                android:id="@+id/TextView01"
                android:layout_height="wrap_content"
                android:text="@string/hello" />

        <LinearLayout
                android:id="@+id/LinearLayout01"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">
                <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="START"
                        android:id="@+id/btnStart" />
                <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="STOP"
                        android:id="@+id/btnStop" />
        </LinearLayout>

   <ScrollView
     android:background="#330000"
     android:fillViewport="true"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content">
      <TextView android:id="@+id/txtLog"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:text="Application Started" />      
   </ScrollView>

</LinearLayout>

Codice (Java): [Seleziona]
Button btnStart,btnStop;
TextView txtLog;

Nel codice creiamo i listener dei Button. Quello per avviare, arresta un WorkerThread se già attivo, prima di avviarne uno nuovo.

Codice (Java): [Seleziona]
btnStart.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
      if (mWorkerThread!=null) {
         mWorkerThread = null;
         txtLog.append("\nrichiesto arresto THREAD #"+Integer.toString(tt)+"\n");
      }
      tt++;
      mWorkerThread = new WorkerThread(mHandler);
      mWorkerThread.start();
      txtLog.append("\nrichiesto avvio THREAD #"+Integer.toString(tt)+"\n");
   }
});


Ultimo elemento, ma non per importanza, dell'activity è l'Handler. Si tratta del codice che sarà automaticamente eseguito quando viene ricevuto uno dei messaggi personalizzati lanciati dal WorkerThread.

Codice (Java): [Seleziona]
final Handler mHandler = new Handler() {
   @Override
   public void handleMessage(Message msg) {
      String rmsg="";
      byte[] rdat;
      switch (msg.what) {
      // messaggio con argomento numerico in arg1
      case MSG_A:
         int nn = 0;
         nn = msg.arg1;
         txtLog.append(Integer.toString(nn)+" ");
         break;
      // messaggio di testo nell'object e lunghezza din arg1
      case MSG_B:
         rdat = (byte[]) msg.obj;
         rmsg = new String(rdat,0,msg.arg1);
         txtLog.append(" "+rmsg+"\n");
         break;
      }
   }
};



NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:[medio] Introduzione ai Thread
« Risposta #1 il: 05 Marzo 2011, 12:25:17 CET »
0
Ciclo infinito

Talvolta può essere utile mantenere il thread in esecuzione, per esempio per eseguire operazioni in background che non hanno una fine ben precisa ma rimangono attive indefinitamente. Un modo scolastico di implementare questo caso è un ciclo infinito all'interno del run() condizionato da una variabile running che fa ripetere il ciclo fintanto che rimane TRUE. Anche in questo caso si utilizza la funzione Thread.sleep() per simulare un carico di lavoro, elemento da rimuovere in una applicazione reale.
 
Codice (Java): [Seleziona]
public void run() {
   // il thread viene ripetuto all'infinito fintanto che running è TRUE
   while (running) {
      // ...
      // codice utente qua
      // ...
   }
}

La variabile viene impostata a TRUE in occasione dello start(), e poi riportata a FALSE quando l'utente preme il bottono STOP.

Codice (Java): [Seleziona]
// avvio del thread
public synchronized void start() {
   running = true;
   super.start();
   Log.i(TAG,"WorkerThread avviato");
}

// arresto del thread
public synchronized void cancel() {
   running = false;
   Log.i(TAG,"WorkerThread fermato");
}

Codice (Java): [Seleziona]
// button per l'avvio del thread
btnStart.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
      if (mWorkerThread!=null) {
         mWorkerThread.cancel();
         mWorkerThread = null;
         txtLog.append("\nrichiesto arresto THREAD #"+Integer.toString(tt)+"\n");
      }
      tt++;
      mWorkerThread = new WorkerThread(mHandler);
      mWorkerThread.start();
      isRunning = true;
      txtLog.append("\nrichiesto avvio THREAD\n");
   }
});

// button per l'arresto del thread
btnStop.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
      if (mWorkerThread!=null) {
         mWorkerThread.cancel();
         mWorkerThread = null;
         txtLog.append("\nrichiesto arresto THREAD\n");
      }
      isRunning = false;
   }
});


Loop con handler di messaggi interno al thread

Nel primo esempio abbiamo visto come inviare un messaggio dal WorkerThread al thread della UI, nel secondo come mantenere in esecuzione il thread indefinitamente. Un'altra struttura, più complessa delle precedenti, permette di creare all'interno del WorkerThread una specie di ciclo infinito, la cui funzione è rimanere costantemente in ascolto di messaggi destinati al thread stesso. Si dice che si crea un Loop di messaggi.

Una applicazione pratica è la creazione di un loop infinito implementato con un thread che si re-invia un messaggio con esecuzione ritardata di un certo tempo (un secondo n questo esempio). Per far questo si provvede ad innescare il loop al primo avvio del thread e per concludere questa volta occorre distruggere esplicitamente il looper dei messaggi.
Codice (Java): [Seleziona]
class WorkerThread extends Thread {
   
   public Handler mCallerHandler,mThreadHandler;
   private int nn = 1;
   Message msgloop;

   public WorkerThread(Handler handler) {
      // salvo l'handler dei messaggi dell'activity chiamante
      mCallerHandler = handler;
      Log.i(TAG,"create WorkerThread");
   }

   public void run() {
      nn = 0;

      // preparazione del looper
      Looper.prepare();

      // handler dei messaggi del thread
      mThreadHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
            String tmsg;
            byte[] tbuf;
            switch (msg.what) {
            case THRMSG_LOOP:
               // codice utente qua
               // ..
               // schedulo nuovamente l'esecuzione tra un secondo
               msgloop = mThreadHandler.obtainMessage(THRMSG_LOOP,-1,-1);
               mThreadHandler.sendMessageDelayed(msgloop,1000);
               break;
            }
         }
      };

      // invio il primo messaggio per innescare il loop
      msgloop = mThreadHandler.obtainMessage(THRMSG_LOOP,-1,-1);
      mThreadHandler.sendMessageDelayed(msgloop,1000);

      // avvio del looper
      Looper.loop();
     
   }

   // avvio del thread
   public synchronized void start() {
      super.start();
      Log.i(TAG,"WorkerThread avviato");
   }
   
   // arresto del thread
   public synchronized void cancel() {
      mThreadHandler.getLooper().quit();
      Log.i(TAG,"WorkerThread fermato");
   }

}
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline gsources75

  • Utente normale
  • ***
  • Post: 327
  • Respect: +9
    • Google+
    • pepigno75
    • devandroid_it
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Nexus S - Vodafone Smart -BB Bold- Iphone 4-
  • Play Store ID:
    Giuseppe+Sorce
  • Sistema operativo:
    Ubuntu-Windows Seven- Mac Lion
Re:[medio] Introduzione ai Thread
« Risposta #2 il: 15 Marzo 2011, 07:16:20 CET »
0
Ottimo tutorial, chiaro.. perfetto.

Non sono mai stato uno sviluppatore Java e la programmazione multi-threading non è nel mio bagaglio culturale...

Una cosa volevo chiederti.
Io ho usato questa sintassi per inviare i messaggio.
Codice (Java): [Seleziona]
Message msg = myHandler.obtainMessage();
                Bundle b = new Bundle();
                b.putInt("currentValue", value);
                msg.setData(b);
                //Log.i("Debug", "notifyValue: "+value);
                this.myHandler.sendMessage(msg);

volevo chiderti per inviare dei dati come array, oggetto devo utilizzare i diversi metodi di Bundle ?

Un' altra domanda so che per aggiornare la UI diventa ovvio e necessario usare un nuovo Thread, ma in quali casi è effettivamente necessario usare questa metodologia.
Ok per caricare dati da un ws, php etc e poi... ?

Caricare un' immagine  ?
La domanda stupida è quella che non si fa

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:[medio] Introduzione ai Thread
« Risposta #3 il: 15 Marzo 2011, 08:02:37 CET »
0
volevo chiderti per inviare dei dati come array, oggetto devo utilizzare i diversi metodi di Bundle ?

Se vedi il codice del primo esempio (ancor meglio nel sorgente completo allegato), nel secondo messaggio spedisco una stringa, dopo averla opportunamente convertita in array di byte (perchè obtainMessage lavora solo con Object, cioè primitivi e array).

Un' altra domanda so che per aggiornare la UI diventa ovvio e necessario usare un nuovo Thread, ma in quali casi è effettivamente necessario usare questa metodologia.Ok per caricare dati da un ws, php etc e poi... ? Caricare un' immagine  ?

Io mi faccio questa domanda: l'operazione può durare più di un secondo? Se si, allora meglio usare un thread (o analogo metodo).
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline gsources75

  • Utente normale
  • ***
  • Post: 327
  • Respect: +9
    • Google+
    • pepigno75
    • devandroid_it
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Nexus S - Vodafone Smart -BB Bold- Iphone 4-
  • Play Store ID:
    Giuseppe+Sorce
  • Sistema operativo:
    Ubuntu-Windows Seven- Mac Lion
Re:[medio] Introduzione ai Thread
« Risposta #4 il: 15 Marzo 2011, 09:09:42 CET »
0
Ok per la logica dei 5 secondi ma caso tipico. ListView di 20 item che devono caricare una piccola immagine. Il Thread devo farlo partire nell' operazione generale o per ogni item per ogni caricamento di immagine devo creare un nuovo thread, io penso la prima.
La domanda stupida è quella che non si fa

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:[medio] Introduzione ai Thread
« Risposta #5 il: 07 Marzo 2012, 08:54:43 CET »
+2
Giusto un piccolo appunto riguardo al codice di esempio postato da bradipao:

Codice (Java): [Seleziona]
public void run() {
   // il thread viene ripetuto all'infinito fintanto che running è TRUE
   while (running) {
      // ...
      // codice utente qua
      // ...
   }
}

E' importante che la variabile running venga dichiarata volatile

Codice (Java): [Seleziona]
protected volatile boolean running;
Questo perchè solitamente si fa una cosa di questo tipo quando si vuole gestire la pausa:

Codice (Java): [Seleziona]
public void pause() {
             running = false;
             while(true) {
        try {
               // Stoppa il thread...
        myThread.join();                               
        // Esci...
              break;
                               
        } catch (InterruptedException e) {
        // Riprova...
  }
 }
}

Se la variabile NON è dichiarata volatile il compilatore può spostarla dove vuole perchè non vede dipendenze evidenti tra il blocco while true e la variabile running. In un caso del genere (running spostata DOPO il while) il thread non termina perchè joined riporterà sempre una interruptedexception visto che non è garantito che running venga settato false.

 :-(

Offline thebestneo

  • Nuovo arrivato
  • *
  • Post: 19
  • Respect: 0
    • Mostra profilo
Re:[medio] Introduzione ai Thread
« Risposta #6 il: 10 Marzo 2012, 16:53:30 CET »
0
Ciao, ho una domanda.
Sto programmando un gioco, e in tutte le guide che ho trovato viene creata una surfaceview nell'activity (che è l'UI thread no?) ma essa viene modificata dal thread che va ad implementare.

Questo va contro l'idea di non modificare l'UI thread da worker thread?

Puoi spiegarmi meglio perchè non ho capito molto bene!

Grazie

Offline Ricky`

  • Amministratore
  • Utente storico
  • *****
  • Post: 3487
  • Respect: +506
    • Github
    • Google+
    • rciovati
    • Mostra profilo
Re:[medio] Introduzione ai Thread
« Risposta #7 il: 10 Marzo 2012, 23:42:47 CET »
0
Giusto un piccolo appunto riguardo al codice di esempio postato da bradipao:

Codice (Java): [Seleziona]
public void run() {
   // il thread viene ripetuto all'infinito fintanto che running è TRUE
   while (running) {
      // ...
      // codice utente qua
      // ...
   }
}

E' importante che la variabile running venga dichiarata volatile

Codice (Java): [Seleziona]
protected volatile boolean running;
Questo perchè solitamente si fa una cosa di questo tipo quando si vuole gestire la pausa:

Codice (Java): [Seleziona]
public void pause() {
             running = false;
             while(true) {
        try {
               // Stoppa il thread...
        myThread.join();                               
        // Esci...
              break;
                               
        } catch (InterruptedException e) {
        // Riprova...
  }
 }
}

Se la variabile NON è dichiarata volatile il compilatore può spostarla dove vuole perchè non vede dipendenze evidenti tra il blocco while true e la variabile running. In un caso del genere (running spostata DOPO il while) il thread non termina perchè joined riporterà sempre una interruptedexception visto che non è garantito che running venga settato false.

 :-(

Due piccole osservazioni:

1)Il metodo join non stoppa il thread ma blocca l'esecuzione del thread che chiama myThread.join() fino a quando il thread myThread non termina.
2)Volatile dice all vm che la variabile deve essere condivisa tra i vari thread, o meglio, ciascuna copia locale deve fare riferimento al valore "globale". non mi è chiaro molto il discorso dello spostamento.
« Ultima modifica: 10 Marzo 2012, 23:46:04 CET da Ricky` »

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:[medio] Introduzione ai Thread
« Risposta #8 il: 11 Marzo 2012, 12:16:56 CET »
0
Due piccole osservazioni:

1)Il metodo join non stoppa il thread ma blocca l'esecuzione del thread che chiama myThread.join() fino a quando il thread myThread non termina.
2)Volatile dice all vm che la variabile deve essere condivisa tra i vari thread, o meglio, ciascuna copia locale deve fare riferimento al valore "globale". non mi è chiaro molto il discorso dello spostamento.
1) Hai ragione, il commento è sbagliato. Lo schema però è abbastanza classico, si trova in molti esempi e libri che utilizzano la surfaceview. In pratica attendi che finisca l'esecuzione del thread myThread (avendo settato running false).
2) Se per assurdo running = false fosse spostato DOPO il while il thread che chiama myThread.join() rimarrebbe in attesa della fine di myThread all'infinito. Purtroppo il ragionamento non è così "assurdo", infatti:

  Java Volatile is Powerful

Cito:

(Ordering)It determines when actions of one Thread seem to happen out of order to other Threads. Compilers and Processors do a lot of optimizations which end up reordering the way instructions are executed. But concurrent programs need some guarantees which restrict some reorderings.

Poichè non esistono dipendenze tra running e quello che c'è nel ciclo while (running non viene letto) è possibile che running = false sia spostato DOPO il blocco while.

Questo è un altro esempio dello stesso comportamento:

http://stackoverflow.com/questions/9187527/volatile-why-prevent-compiler-reorder-code

Questo caso di running volatile utilizzata in questo schema l'ho trovato anche su un libro di programmazione android.

 ;-)

Offline Ricky`

  • Amministratore
  • Utente storico
  • *****
  • Post: 3487
  • Respect: +506
    • Github
    • Google+
    • rciovati
    • Mostra profilo
Re:[medio] Introduzione ai Thread
« Risposta #9 il: 11 Marzo 2012, 13:37:17 CET »
0
1) Hai ragione, il commento è sbagliato. Lo schema però è abbastanza classico, si trova in molti esempi e libri che utilizzano la surfaceview. In pratica attendi che finisca l'esecuzione del thread myThread (avendo settato running false).

Sisi, scusa non era per correggere lo schema ma solo per chiarire cosa fa la join (e farti notare il commento).

Citazione
2) Se per assurdo running = false fosse spostato DOPO il while il thread che chiama myThread.join() rimarrebbe in attesa della fine di myThread all'infinito. Purtroppo il ragionamento non è così "assurdo", infatti:

  Java Volatile is Powerful

Cito:

(Ordering)It determines when actions of one Thread seem to happen out of order to other Threads. Compilers and Processors do a lot of optimizations which end up reordering the way instructions are executed. But concurrent programs need some guarantees which restrict some reorderings.

[...]

Interessante. E' un aspetto che non conoscevo.

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:[medio] Introduzione ai Thread
« Risposta #10 il: 11 Marzo 2012, 13:41:14 CET »
0
Interessante. E' un aspetto che non conoscevo.
Infatti anche io quando ho visto la spiegazione del reordering e l'effetto che ha l'attributo volatile (vista su un libro android) ci sono rimasto molto male!!! Eppure avevo già programmato in Java ma mai avrei pensato che ci fossero queste implicazioni.

Impressionante nel primo link il test di velocità utilizzando volatile invece di meccanismi classici per il lock/unlock!

;-)

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:[medio] Introduzione ai Thread
« Risposta #11 il: 11 Marzo 2012, 14:44:17 CET »
0
Come dice undead è giusto ricorrere al volatile per rendere consistente il contenuto delle variabili condivise.

Però attenzione, la descrizioni del comportamento del Java e le relative raccomandazioni, non è detto che si applichino anche ad Android. In particolare il discorso del volatile è qualcosa di strettamente legato al memory model implementato dalla Java VM, le cui specifiche non si applicano automaticamente anche alla Dalvik VM. Questo come promemoria per ricordare che se a livello di linguaggio si parla comunque di sintassi comune, quando si passa a questioni legate all'implementazione della VM, Java e Android possono comportarsi diversamente.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:[medio] Introduzione ai Thread
« Risposta #12 il: 12 Marzo 2012, 17:18:26 CET »
0
Come dice undead è giusto ricorrere al volatile per rendere consistente il contenuto delle variabili condivise.

Però attenzione, la descrizioni del comportamento del Java e le relative raccomandazioni, non è detto che si applichino anche ad Android. In particolare il discorso del volatile è qualcosa di strettamente legato al memory model implementato dalla Java VM, le cui specifiche non si applicano automaticamente anche alla Dalvik VM. Questo come promemoria per ricordare che se a livello di linguaggio si parla comunque di sintassi comune, quando si passa a questioni legate all'implementazione della VM, Java e Android possono comportarsi diversamente.
Hei ragione, questo è terreno minato, purtroppo.

Io ho letto l'informazione per la prima volta qui (dove è implementato lo stesso schema che ho descritto in questo thread):

http://books.google.it/books?id=ZZx0eRjrhRkC&pg=PA181&lpg=PA181&dq=beginning+android+games+volatile&source=bl&ots=hXkL_feMoW&sig=I8BMwwhSc6wcVccqL0SJD9ZKXE4&hl=en&sa=X&ei=KiBeT4_9KYPKhAempcGoBA&redir_esc=y#v=onepage&q=beginning%20android%20games%20volatile&f=false

E' un libro molto famoso che ha avuto anche più edizioni. Non so se l'autore ha informazioni di prima mano o se ha solo supposto che Dalvik funzioni così.

Facendo una ricerca mi sono spuntate delle domande su stackoverflow in cui un utente che afferma di essere uno svilupattore Dalvik (ovviamente non se sia vero o falso) dice che in configurazioni NON-SMP si può assumere che gingerbread lavori come la VM "classica", da honeycomb questo è valido anche per SMP.

Questo è appunto un campo minato ma onestamente la keyword volatile ha un suo perchè e vedendo la rapida crescita di device android con CPU dual core (e presto quad) via via che passa il tempo (e versioni) credo sia sempre più probabile che la keyword faccia quello che ci si aspetta.

Sarebbe una grave mancanza, visti i benefici che può portare.
 :-)

Offline thebestneo

  • Nuovo arrivato
  • *
  • Post: 19
  • Respect: 0
    • Mostra profilo
Re:[medio] Introduzione ai Thread
« Risposta #13 il: 12 Marzo 2012, 17:24:35 CET »
0
Ehm qualcuno può darmi delucidazioni in merito alla mia domanda di sopra??

 :-)

Grazie!

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:[medio] Introduzione ai Thread
« Risposta #14 il: 12 Marzo 2012, 19:04:11 CET »
0
Ehm qualcuno può darmi delucidazioni in merito alla mia domanda di sopra??

Magari qualcun altro saprà essere più preciso di me, però quando disegni su una SurfaceView non disegni sulla UI, ma su un oggetto di cui prendi il lock (grazie al surfaceholder), poi lo lasci e passa al ridisegno vero e proprio.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store