Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Tastiera gaming MSI GK600 TKL: switch hot-swap, display LCD e tre modalità wireless
Tastiera gaming MSI GK600 TKL: switch hot-swap, display LCD e tre modalità wireless
MSI FORGE GK600 TKL WIRELESS: switch lineari hot-swap, tripla connettività, display LCD e 5 strati di fonoassorbimento. Ottima in gaming, a 79,99 euro
DJI Osmo Pocket 4: la gimbal camera tascabile cresce e ha nuovi controlli fisici
DJI Osmo Pocket 4: la gimbal camera tascabile cresce e ha nuovi controlli fisici
DJI porta un importante aggiornamento alla sua linea di gimbal camera tascabili con Osmo Pocket 4: sensore CMOS da 1 pollice rinnovato, gamma dinamica a 14 stop, profilo colore D-Log a 10 bit, slow motion a 4K/240fps e 107 GB di archiviazione integrata. Un prodotto pensato per i creator avanzati, ma che convince anche per l'uso quotidiano
Sony INZONE H6 Air: il primo headset open-back di Sony per giocatori
Sony INZONE H6 Air: il primo headset open-back di Sony per giocatori
Il primo headset open-back della linea INZONE arriva a 200 euro con driver derivati dalle cuffie da studio MDR-MV1 e un peso record di soli 199 grammi
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 25-02-2007, 16:15   #1
lovaz
Senior Member
 
L'Avatar di lovaz
 
Iscritto dal: Jul 2002
Messaggi: 4334
[JAVA] Worker thread, giusto così?

Salve,

devo fare un update di un componente swing - setText o setIcon - con dei
dati che impiego un po' a calcolare, e quindi devo tirare via la computazione
dall'EDT, pena "freeze" della gui.

C'è anche da dire che se durante l'esecuzione del worker thread ne lancio un altro
voglio che sia quest'ultimo ad aggiornare il componente.
In pratica le vecchie computazioni non mi interessano.

Ho impostato la classe così:
Codice:
public class IDTextUpdater
	implements Runnable
{
	...
	private static Thread lastThread;
	...

/* qui sono nel costruttore */
		// update last thread variable
		lastThread = new Thread(this);
		lastThread.start();
/* fine costruttore */

/* nel metodo run()... */
		// lavora...
		...
		if( lastThread != Thread.currentThread() )
			return;

		// aggiorna il componente
		SwingUtilities.invokeLater( new Runnable() {...} )
/* fine run() */
Il tutto sembra funzionare egregiamente, ma siccome con la concorrenza
non si sa mai, vedete qualcosa che potrebbe non andare?

Grazie.
lovaz è offline   Rispondi citando il messaggio o parte di esso
Old 25-02-2007, 21:08   #2
thebol
Senior Member
 
Iscritto dal: Dec 2000
Città: bologna
Messaggi: 1309
se la computazione è grossa nel costruttore potresti mettere uno stop thread(nn ricordo se è deprecato, cmq bloccarlo in qualche maniera).

Cmq se per caso viene creato un nuovo updater, e il vecchio è bloccato dopo il controllo if( lastThread != Thread.currentThread() ), e il nuovo updater finisce prima che il controllo ritorni al vecchio updater, puoi trovarti con la textbox valorizzata col risultato del vecchio updater.
thebol è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2007, 10:50   #3
lovaz
Senior Member
 
L'Avatar di lovaz
 
Iscritto dal: Jul 2002
Messaggi: 4334
Grazie della risposta.

Sì, stop è deprecato, il modo pulito per terminare un thread è uscire dal metodo run().

Per il resto forse hai ragione, ma d'altra parte non saprei come fare diversamente...

Forse mettendo statici i componenti da aggiornare e mettendoli a null
nel costruttore? Il tutto sincronizzato ovviamente.
lovaz è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2007, 12:10   #4
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
lastThread deve essere volatile o incapsulato in un AtomicReference.

Come indicato da thebol, il programma che hai scritto non fa quello che vorresti (eseguire solo l'ultimo aggiornamento grafico). Tra le possibili soluzioni io vedrei bene una doppia coda di consumazione di eventi Runnable. Una per le computazioni in background, una per gli aggiornamento grafici. Quando immetti una computazione, che potrebbe essere rappresentata con;

Codice:
interface MultiTask {
    Runnable getBackgroundTask();
    Runnable getAWTTask();
}
infili nella coda dei compiti in background il prodotto di getBackgroundTask(), svuoti la coda dei compiti AWT e immetti il prodotto di getAWTTask(). L'uso di una coda (LinkedBlockingQueue) garantisce la sequenzialità dell'esecuzione di compiti AWT non più annullabili (già offerti prima di un clear()). Lo stesso tipo di struttura dati per i compiti in background ti permette di delegare l'esecuzione degli stessi ad un pool di Thread, idealmente più efficiente di un Thread per computazione.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2007, 12:29   #5
lovaz
Senior Member
 
L'Avatar di lovaz
 
Iscritto dal: Jul 2002
Messaggi: 4334
Ok, ci lavoro su e vi faccio sapere.
lovaz è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2007, 17:56   #6
lovaz
Senior Member
 
L'Avatar di lovaz
 
Iscritto dal: Jul 2002
Messaggi: 4334
Allora, per i thread pool e le code bloccanti vedrò più avanti,
magari li userò per un altra cosetta che ho in mente.

Intanto ho modificato il codice così:
Codice:
	private static IDTextUpdater lastUpdater; // tolto lastThread
	private boolean stopped;
	...
/* qui sono nel costruttore */
		this.stopped = false;
		
		if( lastUpdater != null )
			lastUpdater.stop();
		
		lastUpdater = this;
		new Thread( this ).start();
/* fine costruttore */

	void stop()
	{
		stopped = true;
	}

/* nel metodo run()... */
		// lavora...
		...
		if( stopped )
			return;

		SwingUtilities.invokeLater( new Runnable()
			{ if( !stopped ) /* update componente*/...} );
/* fine run() */
Che ne dite?
lovaz è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2007, 18:12   #7
^TiGeRShArK^
Senior Member
 
L'Avatar di ^TiGeRShArK^
 
Iscritto dal: Jul 2002
Città: Reggio Calabria -> London
Messaggi: 12112
e xkè non usare SwingWorker anzikè reinventare la ruota?
ehm...
ovviamente se epuoi usare java 6
__________________
^TiGeRShArK^ è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2007, 18:17   #8
lovaz
Senior Member
 
L'Avatar di lovaz
 
Iscritto dal: Jul 2002
Messaggi: 4334
Devo usare java5, e comunque non risparmierei una riga di codice...
lovaz è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2007, 18:35   #9
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
non potendo essere final, lastUpdater e stopper devono essere volatile o incapsulati in un AtomicReference/AtomicBoolean o il loro accesso deve essere contenuto in un blocco sincronizzato.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2007, 19:39   #10
thebol
Senior Member
 
Iscritto dal: Dec 2000
Città: bologna
Messaggi: 1309
Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
non potendo essere final, lastUpdater e stopper devono essere volatile o incapsulati in un AtomicReference/AtomicBoolean o il loro accesso deve essere contenuto in un blocco sincronizzato.
*
in quella maniera hai solo spostato piu avanti nel codice il controllo, ma non l'hai eliminato o reso sincronizzato rispetto a piu thread.

ps che roba sono le atomicQualcosa?
thebol è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2007, 20:36   #11
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Sono i nuovi volatile. Se prima si diceva:

private volatile boolean pimpumpam...

oggi si dovrebbe prediligere:

private final AtomicBoolean pimpumpam...

C'è un Atomic per tipo, con AtomicReference asso piglia tutto.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2007, 20:56   #12
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Credo che il problema d'ordine sia stato risolto. Quel booleano, uno per ogni Thread, viene controllato in un unico Thread, l'AWT Event Dispatcher. Poichè il Runnable è premuto nella coda degli eventi AWT, esiste una relazione d'ordine tra gli eventi.

Se il Thread è bloccato nell'esecuzione del runnable allora non può verificarsi l'aggiornamento grafico del Thread successivo perchè il Thread successivo ha premuto il suo evento nella stessa coda.

Se l'evento del Thread precedente è premuto nella coda prima di quello del Thread successivo, allora quando sarà eseguito il runnable del Thread precedente il valore di stopped sarà necessariamente (volatile o Atomic) true.

Insomma, mi pare che funzioni. A naso e alla 22:00, ma direi che funziona. Lì. Quello che mi lascia perplesso è "lastUpdater".

E' possibile che un Thread a cui è affidata l'esecuzione di un aggiornamento precedente arrivi a bloccare un Thread a cui è affidata l'esecuzione dell'aggiornamneto successivo.

io eseguo:

thread 1 (aggiornamento ui vecchio) -> via
thread 2 (aggiornamento ui nuovo) -> via

thread 1 sta per eseguire: lastUpdater.stop

thread 2 tira la volata e arriva fino a lastUpdater = this
thread 1 esegue lastUpdate.stop e impedisce l'aggiornamento UI di Thread 2

L'ultimo aggiornamento grafico non viene eseguito.

O mi sono perso qualcosa?
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2007, 21:19   #13
thebol
Senior Member
 
Iscritto dal: Dec 2000
Città: bologna
Messaggi: 1309
Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
Credo che il problema d'ordine sia stato risolto. Quel booleano, uno per ogni Thread, viene controllato in un unico Thread, l'AWT Event Dispatcher. Poichè il Runnable è premuto nella coda degli eventi AWT, esiste una relazione d'ordine tra gli eventi.

Se il Thread è bloccato nell'esecuzione del runnable allora non può verificarsi l'aggiornamento grafico del Thread successivo perchè il Thread successivo ha premuto il suo evento nella stessa coda.

Se l'evento del Thread precedente è premuto nella coda prima di quello del Thread successivo, allora quando sarà eseguito il runnable del Thread precedente il valore di stopped sarà necessariamente (volatile o Atomic) true.

Insomma, mi pare che funzioni. A naso e alla 22:00, ma direi che funziona. Lì.

si avevo letto troppo velocemente il codice, mi sa che hai ragione tu

Quote:
Quello che mi lascia perplesso è "lastUpdater".

E' possibile che un Thread a cui è affidata l'esecuzione di un aggiornamento precedente arrivi a bloccare un Thread a cui è affidata l'esecuzione dell'aggiornamneto successivo.

io eseguo:

thread 1 (aggiornamento ui vecchio) -> via
thread 2 (aggiornamento ui nuovo) -> via

thread 1 sta per eseguire: lastUpdater.stop

thread 2 tira la volata e arriva fino a lastUpdater = this
thread 1 esegue lastUpdate.stop e impedisce l'aggiornamento UI di Thread 2

L'ultimo aggiornamento grafico non viene eseguito.

O mi sono perso qualcosa?
mi sa che hai ragione...

...tanto per far capire quanto sia complicato giocare con i thread
thebol è offline   Rispondi citando il messaggio o parte di esso
Old 27-02-2007, 09:13   #14
lovaz
Senior Member
 
L'Avatar di lovaz
 
Iscritto dal: Jul 2002
Messaggi: 4334
Ma ragazzi, il costruttore, in cui chiamo lastUpdater.stop(), viene eseguito nell'EDT,
che e' un unico thread, quindi sequenzialmente, e non parallelamente, o sbaglio?

lastUpdater non e' un thread, e' un Runnable eseguito dal thread.
lovaz è offline   Rispondi citando il messaggio o parte di esso
Old 27-02-2007, 12:40   #15
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Se lastUpdater ha un metodo stop è un po' più di un Runnable. Che non sia un Thread l'ho capito .

Se il costruttore è eseguito dall'AWT Event Dispatcher allora, contrariamente al classico libro giallo, la trama si semplifica.

Il caso che mi lasciava perplesso non si verifica più. lastUpdater non deve essere volatile/atomic: è usato da un solo Thread dunque che sia aggiornata la sola copia locale di quel campo è indifferente.

Deve ancora essere volatile/atomic "stopped", perchè il suo valore è letto da un Thread e scritto da un altro.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 27-02-2007, 13:17   #16
lovaz
Senior Member
 
L'Avatar di lovaz
 
Iscritto dal: Jul 2002
Messaggi: 4334
Ma l'assegnamento a un boolean e' comunque atomico... o no?
lovaz è offline   Rispondi citando il messaggio o parte di esso
Old 27-02-2007, 14:06   #17
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
E' un inghippo terminologico. Sì, l'assegnamento è atomico, nello stesso senso in cui non è atomico l'assegnamento ad un long.

Ma se portiamo la faccenda in un contesto concorrente, questa atomicità non è più sufficiente. I thread operano su copie locali dei campi. Tutte le operazioni che un Thread esegue su un campo sono operazioni il cui effetto è limitato alla copia locale di quel campo. Così se in un Thread assegno al campo ciccio il valore N ciò che accade, secondo le specifiche del linguaggio, è che la copia locale del campo ciccio, che esiste solo per quel tal Thread, assume il valore N. Il campo "vero", quello che esiste nell'heap, resta inalterato. Lo stesso vale per la lettura. Quando un Thread legge il valore di un campo legge il valore della copia locale di quel campo.

I valori iniziali dei campi usati dai Thread sono quelli esistenti nell'heap. Poichè ogni volta che un Thread muta il valore di un campo tale mutazione è propria della sola copia locale di quel campo, in linea di principio i campi hanno sempre e solo il valore iniziale predefinito (null per i reference, 0 per i numerici, '\0' per i caratteri, false per i boolean).

Ci sono poi una serie di norme che stabiliscono quando la manipolazione che un Thread opera su un campo risulta visibile ad altri Thread. Una di queste coinvolge l'uso del modificatore volatile (e del suo alter-ego in Java 5 rappresentato dagli AtomicBlaBla). Detto terra-terra, quando assegni un valore ad un campo volatile quel valore finisce nell'heap e sarà quindi il valore ottenuto da altri Thread quando accederanno a quel campo.

Nel nostro caso noi ci chiediamo: qual'è il valore del campo "stopped". Basandoci sulle norme del modello di memoria del linguaggio di programmazione Java noi sappiamo che.

1. stopped ha sicuramente il valore di inizializzazione predefinito "false".
2. nel costruttore quel valore cambia ma quello che veramente cambia è il valore di una copia locale (ad un Thread) di stopped.
3. nel metodo run, il valore certo di stopped è false se il run sia eseguito da un Thread diverso da quello che ha invocato il costruttore.
4. nel metodo run del Runnable usato in invokeLater, il valore certo di stopped è ancora false se il costruttore non sia stato eseguito dall'AWT Event Dispatcher. E' true se, come nel nostro caso, il costruttore sia stato eseguito dall'AWT Event Dispatcher.

Ecco perchè dico che "stopped" deve essere volatile: perchè il metodo run è certamente eseguito da un Thread diverso dall'AWT Event Dispatcher.

Non serve che sia volatile "lastUpdated". In questo caso, infatti, hai garantico che il costruttore, in cui il valore di lastUpdated cambia, sarà eseguito sempre e soltanto da un solo Thread. Questo Thread lavorerà sulla sua copia locale e questa copia locale assumerà di volta in volta valori diversi.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 27-02-2007, 16:00   #18
lovaz
Senior Member
 
L'Avatar di lovaz
 
Iscritto dal: Jul 2002
Messaggi: 4334
Ah, ok...
Grazie.
lovaz è offline   Rispondi citando il messaggio o parte di esso
Old 28-02-2007, 09:00   #19
lovaz
Senior Member
 
L'Avatar di lovaz
 
Iscritto dal: Jul 2002
Messaggi: 4334
Una curiosita': questa storia delle variabili locali ai thread vale anche per le statiche?
lovaz è offline   Rispondi citando il messaggio o parte di esso
Old 28-02-2007, 09:33   #20
thebol
Senior Member
 
Iscritto dal: Dec 2000
Città: bologna
Messaggi: 1309
a naso direi di si, ma aspetterei il guru per la conferma
thebol è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Tastiera gaming MSI GK600 TKL: switch hot-swap, display LCD e tre modalità wireless Tastiera gaming MSI GK600 TKL: switch hot-swap, ...
DJI Osmo Pocket 4: la gimbal camera tascabile cresce e ha nuovi controlli fisici DJI Osmo Pocket 4: la gimbal camera tascabile cr...
Sony INZONE H6 Air: il primo headset open-back di Sony per giocatori Sony INZONE H6 Air: il primo headset open-back d...
Nutanix cambia pelle: dall’iperconvergenza alla piattaforma full stack per cloud ibrido e IA Nutanix cambia pelle: dall’iperconvergenza alla ...
Recensione Xiaomi Pad 8 Pro: potenza bruta e HyperOS 3 per sfidare la fascia alta Recensione Xiaomi Pad 8 Pro: potenza bruta e Hyp...
SK hynix ha avviato la produzione di mod...
Microsoft non ha pace sul Menu Start di ...
Cinque robot aspirapolvere e lavapavimen...
De'Longhi Tasciugo AriaDry: il deumidifi...
Robot più veloci dell'uomo: la me...
Palantir-manifesto, tra tecnologia e ide...
Classifica Amazon top 10 sconvolta: nuov...
DRAM, domanda fuori controllo: produzion...
HUDIMM e HSODIMM: la risposta dell'indus...
Il riconoscimento facciale è un'a...
Un affare pazzesco, finché dura o...
Lava a 75°, è un 21.000Pa con...
iPhone 18 Pro: il componente che garanti...
DeepL alza il livello: con Voice-to-Voic...
Apple sta utilizzando sempre più ...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 09:21.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Served by www3v