Torna indietro   Hardware Upgrade Forum > Software > Programmazione

OPPO Find X9 Pro: il camera phone con teleobiettivo da 200MP e batteria da 7500 mAh
OPPO Find X9 Pro: il camera phone con teleobiettivo da 200MP e batteria da 7500 mAh
OPPO Find X9 Pro punta a diventare uno dei riferimenti assoluti nel segmento dei camera phone di fascia alta. Con un teleobiettivo Hasselblad da 200 MP, una batteria al silicio-carbonio da 7500 mAh e un display da 6,78 pollici con cornici ultra ridotte, il nuovo flagship non teme confronti con la concorrenza, e non solo nel comparto fotografico mobile. La dotazione tecnica include il processore MediaTek Dimensity 9500, certificazione IP69 e un sistema di ricarica rapida a 80W
DJI Romo, il robot aspirapolvere tutto trasparente
DJI Romo, il robot aspirapolvere tutto trasparente
Anche DJI entra nel panorama delle aziende che propongono una soluzione per la pulizia di casa, facendo leva sulla propria esperienza legata alla mappatura degli ambienti e all'evitamento di ostacoli maturata nel mondo dei droni. Romo è un robot preciso ed efficace, dal design decisamente originale e unico ma che richiede per questo un costo d'acquisto molto elevato
DJI Osmo Nano: la piccola fotocamera alla prova sul campo
DJI Osmo Nano: la piccola fotocamera alla prova sul campo
La nuova fotocamera compatta DJI spicca per l'abbinamento ideale tra le dimensioni ridotte e la qualità d'immagine. Può essere installata in punti di ripresa difficilmente utilizzabili con le tipiche action camera, grazie ad una struttura modulare con modulo ripresa e base con schermo che possono essere scollegati tra di loro. Un prodotto ideale per chi fa riprese sportive, da avere sempre tra le mani
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 23-06-2014, 22:57   #1
SubSeven
Member
 
L'Avatar di SubSeven
 
Iscritto dal: Nov 2009
Messaggi: 105
[JAVA] Multithreading & Swing

"Meglio un morto in casa, che una professoressa inaffidabile sull'uscio"

Tra le sensazioni più belle che la vita universitaria mi sta facendo sperimentare, sicuramente rientra il fatto di dover sostenere prove d'esame che contengono argomenti mai trattati a lezione. Non sarò il primo, ma nemmeno l'ultimo

Veniamo a noi.
Per l'esame di Programmazione Orientata agli Oggetti, avrò da sviluppare un programmino in Java (Netbeans) all'interno del quale dovrò gestire la mutua esclusione tra più thread che condividono una struttura dati in comune.

Secondo il testo: "L'applicativo da implementare consiste di un main che istanzia 4 thread di gestione (T1, T2, T3, T4) [...] Ciascun Thread dispone di una propria GUI che:
• espone un bottone: “inserisci” che se premuto causa l'inserimento di tale utente all'interno del Database (tale operazione di produzione deve essere implementata in maniera esclusiva rispetto agli altri Thread e in coerenza con
l'algoritmo dei produttori/consumatori)
• espone un bottone “cancella” che se premuto causa l'estrazione (e quindi cancellazione) del medesimo utente dal Database (tale operazione di consumo deve essere implementata in maniera esclusiva rispetto agli altri Thread e
in coerenza con l'algoritmo dei produttori/consumatori)"


Creata la GUI (un JFrame), dal main istanzio 4 Thread e li eseguo:

Codice:
Thread T1 = new Thread (new GUI(db));
        T1.start();
        Thread T2 = new Thread (new GUI(db));
        T2.start();
        Thread T3 = new Thread (new GUI(db));
        T3.start();
        Thread T4 = new Thread (new GUI(db));
        T4.start();
Quello che ottengo è la visualizzazione di 4 finestre diverse, tutte con la stessa GUI.
Ogni finestra ha dei campi di testo per l'inserimento di dati, un pulsante INSERISCI (per aggiungere un elemento alla struttura dati) e un pulsante RIMUOVI (per rimuoverlo, appunto).
Sia l'inserimento, sia la rimozione mettono in Sleep (per 2 secondi) il thread da cui è stata lanciata l'azione.
Il corretto svolgimento dell'esercizio prevede che, una volta iniziata l'operazione con il thread 1, cliccando sul pulsante del thread 2, l'azione di quest'ultimo non parta prima del completamento di quella iniziata nel thread 1.

Qual è il problema?
Dal momento che faccio eseguire il codice per l'inserimento/cancellazione di un elemento dalla struttura dati direttamente dal bottone della GUI, visto che quest'ultima azione viene affidata all'EDT (Event Dispatching Thread), mi si bloccano le UI di tutte e 4 le finestre aperte, non consentendomi di fare altro prima della fine del processo avviato.

La mia domanda è: come fare a far eseguire il codice su 4 thread veramente separati?
__________________
CPU Intel Core i3-3217U @1.80GHz |RAM 4GB DD3 | HD Samsung Solid State Drive 840 | S.O. Microsoft Windows 7

Ultima modifica di SubSeven : 23-06-2014 alle 23:01.
SubSeven è offline   Rispondi citando il messaggio o parte di esso
Old 24-06-2014, 06:43   #2
sottovento
Senior Member
 
L'Avatar di sottovento
 
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
Ti capisco. Sono passati (troppi) anni dalla laurea, ma ho ancora il rancore verso certi professori.

Veniamo a noi. Ovviamente occorrerebbe vedere il software che hai scritto, ma da quanto hai raccontato, hai ALMENO 6 thread che girano nel tuo sistema:
- il thread main
- il thread di Swing per la gestione dell'HMI
- T1, T2, T3 e T4

Non importa quante finestre decidi di aprire, saranno tutte gestite dal thread di cui sopra.
E' quindi evidente che se, nella callback (vale a dire nella actionPerformed() in risposta alla pressione di un bottone) metti un ritardo di 2 secondi, allora TUTTE le finestre saranno bloccate per due secondi, perche' il thread swing dovra' eseguire quella pausa e non avra' modo di rispondere agli altri eventi dell'HMI (pressione di altri bottoni, disegno delle finestre, ecc.).
La pausa deve essere fatta dai TUOI thread t1...t4, non dal thread (unico) dell'HMI.

Puoi postare qui il codice, se ti va. Per inciso: non e' che la prof. copia gli esempi direttamente dal libro alla lavagna? Mi e' capitato anche questo
__________________
In God we trust; all others bring data
sottovento è offline   Rispondi citando il messaggio o parte di esso
Old 24-06-2014, 10:54   #3
SubSeven
Member
 
L'Avatar di SubSeven
 
Iscritto dal: Nov 2009
Messaggi: 105
Quote:
Originariamente inviato da sottovento Guarda i messaggi
Per inciso: non e' che la prof. copia gli esempi direttamente dal libro alla lavagna? Mi e' capitato anche questo
Guarda, la mia professoressa è così scarsa che per sbaglio ha proiettato, davanti 100 persone, un documento word con tutte le sue password... il tutto senza nemmeno accorgersene!

Comunque, posto il codice, così almeno rendo un'idea su come ho impostato l'applicativo

Main.java
Codice:
public class Main {
    public static void main (String[] args) {
        ArrayList<Utente> l = new ArrayList<>();
        Database db = new Database (l);                 // Passo la mia struttura dati ad un oggetto di tipo Database, nel quale sono contenuti tutti i metodi synchronized
      
        Thread T1 = new Thread (new GUI(db));
        T1.start();
        Thread T2 = new Thread (new GUI(db));
        T2.start();
        Thread T3 = new Thread (new GUI(db));
        T3.start();
        Thread T4 = new Thread (new GUI(db));
        T4.start();   
    }
Database.java - è la classe che contiene i metodi per l'inserimento/cancellazione di un nuovo elemento all'interno della struttura dati (per adesso la variabile booleana writeLock la sto usando solo per la funzione di inserimento; una volta raggiunto il risultato voluto estenderò la sua implementazione anche alla funzione cancellaUtente )

Codice:
public class Database {

    ArrayList<Utente> l;
    boolean writeLock;
    int readCount;

    public Database(ArrayList<Utente> l) {
        this.l = l;
        writeLock = false;
        readCount = 0;

    }

    private void writeLock() {
        while (writeLock) {
            try {

                Thread.currentThread().wait();

            } catch (InterruptedException ex) {
                Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        this.writeLock = true;

    }

    private void writeUnlock() {

        try {
            Thread.sleep(2000);
        } catch (InterruptedException ex) {
            Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
        }
        this.writeLock = false;

        Thread.currentThread().notifyAll();
    }

    public synchronized void nuovoUtente(Utente nuovo) throws UtentePresenteEx {
        writeLock();
        if (l.isEmpty() || (verificaUtente(nuovo) == null)) {
            l.add(nuovo);

        } else {
            throw new UtentePresenteEx(nuovo.getCodice_fiscale());
        }

        writeUnlock();

    }

    private synchronized Object verificaUtente(Utente nuovo) {

        Iterator i = l.iterator();
        while (i.hasNext()) {
            Object ricerca = i.next();
            if (nuovo.compareTo(ricerca) == 1) {
                return ricerca;
            }
        }
        return null;
    }

    public synchronized boolean cancellaUtente(Utente ricerca) throws UtenteNonPresenteEx {

        Object risultato = verificaUtente(ricerca);
        if (risultato != null) {
            if (l.remove((Utente) risultato)) {
                return true;
            } else {
                return false;
            }

        }
        return false;
    }

}
GUI.java (JFrame)
Codice:
public class GUI extends javax.swing.JFrame implements Runnable {

    Database db;

    public GUI(Database db) {
        initComponents();
        this.db = db;
        this.setTitle("Prova JAVA - "+ Thread.currentThread().getName());
    }

    private void inserisciBtnActionPerformed(java.awt.event.ActionEvent evt) {                                             
        inserisciBtn.setEnabled(false);
        String nome = nomeTxt1.getText();
        String cognome = cognomeTxt1.getText();
        String codFisc = codFiscTxt.getText();
        int eta = Integer.parseInt(etaTxt.getText());
        String sesso = sessoTxt.getText();
        String mail = mailTxt.getText();
        Utente nuovo = new Utente(codFisc, nome, cognome, eta, sesso, mail);
        
        try {
            db.nuovoUtente(nuovo);
        } catch (UtentePresenteEx ex) {
            Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
        }
    }                                            

    private void cancellaBtnActionPerformed(java.awt.event.ActionEvent evt) {                                            
        String codice_fiscale = codFiscTxt.getText();
        Utente ricerca = new Utente(codice_fiscale, null, null, 0, null, null);
        try {
            if (db.cancellaUtente(ricerca)) {
                JOptionPane.showMessageDialog(null, "Utente rimosso con successo", "Informazione", JOptionPane.INFORMATION_MESSAGE);
                deletedUsersTxt.append(ricerca.getCodice_fiscale()+"\n");
            } else throw new UtenteNonPresenteEx(ricerca.getCodice_fiscale());            
        } catch (UtenteNonPresenteEx ex) {
            JOptionPane.showMessageDialog(null, ex.getMessage(), "Errore", JOptionPane.ERROR_MESSAGE);
        } 
    }                                           
    
    @Override
    public void run() {
        setVisible(true);

    }
}
Utente.java - nemmeno a postarla, è una banale classe con i campi (nome, cognome, codice_fiscale, eta, sesso, mail) e relativi Getter & Setter.

Allego, per sicurezza, anche un zip con tutto il progetto (https://dl.dropboxusercontent.com/u/...3/Palestra.zip)

Quote:
Originariamente inviato da sottovento Guarda i messaggi
La pausa deve essere fatta dai TUOI thread t1...t4, non dal thread (unico) dell'HMI.
Ecco, dovrei fare proprio questo! Ma come?
__________________
CPU Intel Core i3-3217U @1.80GHz |RAM 4GB DD3 | HD Samsung Solid State Drive 840 | S.O. Microsoft Windows 7

Ultima modifica di SubSeven : 24-06-2014 alle 10:59.
SubSeven è offline   Rispondi citando il messaggio o parte di esso
Old 24-06-2014, 16:39   #4
sottovento
Senior Member
 
L'Avatar di sottovento
 
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
Scusa il ritardo, sono dovuto partire per le mie "ferie forzate" (ogni mese devo lasciare l'Arabia Saudita e passare qualche giorno in Bahrain per motivi di visto).

Scarichero' la traccia che hai lasciato. Ad ogni modo, i tuoi thread non fanno granche', visto che lavorano solo per qualche microsecondo: rendono la GUI visibile e basta, poi muoiono. Quindi i thread T1...T4 praticamente NON esistono!

Ora ho un po' di cose da fare, poi leggo la traccia. A presto
__________________
In God we trust; all others bring data
sottovento è offline   Rispondi citando il messaggio o parte di esso
Old 24-06-2014, 16:41   #5
SubSeven
Member
 
L'Avatar di SubSeven
 
Iscritto dal: Nov 2009
Messaggi: 105
Quote:
Originariamente inviato da sottovento Guarda i messaggi
Scusa il ritardo, sono dovuto partire per le mie "ferie forzate" (ogni mese devo lasciare l'Arabia Saudita e passare qualche giorno in Bahrain per motivi di visto).

Scarichero' la traccia che hai lasciato. Ad ogni modo, i tuoi thread non fanno granche', visto che lavorano solo per qualche microsecondo: rendono la GUI visibile e basta, poi muoiono. Quindi i thread T1...T4 praticamente NON esistono!

Ora ho un po' di cose da fare, poi leggo la traccia. A presto
Ok, attendo allora
__________________
CPU Intel Core i3-3217U @1.80GHz |RAM 4GB DD3 | HD Samsung Solid State Drive 840 | S.O. Microsoft Windows 7
SubSeven è offline   Rispondi citando il messaggio o parte di esso
Old 24-06-2014, 21:07   #6
VICIUS
Senior Member
 
L'Avatar di VICIUS
 
Iscritto dal: Oct 2001
Messaggi: 11471
Io toglierei qui quattro thread che come ha già detto sottovento hanno vita breve. Piuttosto crea un ExecutorService e passalo alla gui così può usarlo per eseguire dei Runnable contenenti la chiamata al database e la sleep in un thread separato senza bloccare l'interfaccia.

Ti lascio un paio di link alla documentazione per partire
http://docs.oracle.com/javase/7/docs...orService.html
http://docs.oracle.com/javase/7/docs...Executors.html
http://docs.oracle.com/javase/7/docs.../Callable.html
VICIUS è offline   Rispondi citando il messaggio o parte di esso
Old 25-06-2014, 01:56   #7
sottovento
Senior Member
 
L'Avatar di sottovento
 
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
VICIUS, hai perfettamente ragione ma questo e' un esercizio e da quanto ho capito i 4 thread sono richiesti. Occorre provare a dar loro un senso

Ho dato un'occhiata veloce al codice. Per prima cosa, devo dire che mi piace il tuo stile, sei molto pulito. Quindi le modifiche non saranno difficili da eseguire.

La prima modifica da fare riguarda entrambi i metodi inserisciBtnActionPerformed() e cancellaBtnActionPerformed().
Questa e' la tua implementazione:
Codice:
    private void inserisciBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_inserisciBtnActionPerformed
        inserisciBtn.setEnabled(false);
        String nome = nomeTxt1.getText();
        String cognome = cognomeTxt1.getText();
        String codFisc = codFiscTxt.getText();
        int eta = Integer.parseInt(etaTxt.getText());
        String sesso = sessoTxt.getText();
        String mail = mailTxt.getText();
        Utente nuovo = new Utente(codFisc, nome, cognome, eta, sesso, mail);
        
        try {
            db.nuovoUtente(nuovo);
        } catch (UtentePresenteEx ex) {
            Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
        }
    }//GEN-LAST:event_inserisciBtnActionPerformed

    private void cancellaBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancellaBtnActionPerformed
        String codice_fiscale = codFiscTxt.getText();
        Utente ricerca = new Utente(codice_fiscale, null, null, 0, null, null);
        try {
            if (db.cancellaUtente(ricerca)) {
                JOptionPane.showMessageDialog(null, "Utente rimosso con successo", "Informazione", JOptionPane.INFORMATION_MESSAGE);
                deletedUsersTxt.append(ricerca.getCodice_fiscale()+"\n");
            } else throw new UtenteNonPresenteEx(ricerca.getCodice_fiscale());            
        } catch (UtenteNonPresenteEx ex) {
            JOptionPane.showMessageDialog(null, ex.getMessage(), "Errore", JOptionPane.ERROR_MESSAGE);
        } 
    }//GEN-LAST:event_cancellaBtnActionPerformed
La prima istruzione
Codice:
        inserisciBtn.setEnabled(false);
disabilita il bottone, ma non c'e' un codice complementare che lo riattiva. Se il problema e' quello di farlo riattivare dopo 2 secondi, puoi risolverlo modificando direttamente all'interno dei due metodi che hai scritto (ATTENZIONE - quanto scrivo e' java 8):
Codice:
        javax.swing.Timer timer = new javax.swing.Timer(2000, event -> inserisciBtn.setEnabled(true));
        timer.setRepeats(false);
        timer.start();
Alla scadenza del timer, il bottone verra' riattivato.

Il secondo problema e' che l'inserimento/cancellazione viene fatto direttamente da questi due metodi. Devi togliere l'inserimento/cancellazione da li', metterli nei thread T1...T4 ed inventarti un modo per far comunicare i due thread. Secondo me il modo piu' semplice (di cui spesso abuso) e' utilizzare le ArrayBlockingQueue<>. In pratica, Tx e la corrispondente coda si parlano attraverso questa coda: la gui inserisce l'oggetto e il thread tx lo legge ed esegue l'operazione. Semplice, no?
Facendo cosi' dai un senso ai thread e non blocchi l'HMI.

Infine: probabilmente ti e' scappato il fatto che il tuo codice genera un
java.lang.IllegalMonitorStateException

poiche' l'istruzione

Codice:
Thread.currentThread().notifyAll();
e' fuori da qualsiasi blocco sincronizzato, pertanto l'istruzione non e' valida.
Fai attenzione: questo e' il motivo che ti faceva sembrare che l'HMI fosse incartata (insieme ovviamente alla disabilitazione del bottone). Se avessi messo questa istruzione al posto giusto, probabilmente non ti saresti accorto di nulla e non ti saresti chiesto se effettivamente i thread stavano girando correttamente. In pratica, l'errore ti ha dato la possibilita' di "vedere" esattamente le cose come stanno.

Riassumento, i primi passi secondo me sono:
1 - riabilitare il bottone
2 - fare in modo the i thread T1...T4 abbiano un senso, cioe' che dentro il metodo run() ci sia del codice, ed il codice deve essere un ciclo (infinito) che legge dalla coda bloccante che arriva da HMI. Una volta letto il dato (ed un codice operativo che specifica cosa farne), inserisce o cancella il dato;
3 - ripensare lock dei thread, vale a dire la parte che ti fallisce. Pero' io affronterei prima i punti 1 e 2. Per fare questa parte, lascerei stare i monitor ed utilizzerei l'oggetto Semaphore, sempre che la prima soluzione non ti sia stata imposta...

tienici aggiornati
__________________
In God we trust; all others bring data
sottovento è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


OPPO Find X9 Pro: il camera phone con teleobiettivo da 200MP e batteria da 7500 mAh OPPO Find X9 Pro: il camera phone con teleobiett...
DJI Romo, il robot aspirapolvere tutto trasparente DJI Romo, il robot aspirapolvere tutto trasparen...
DJI Osmo Nano: la piccola fotocamera alla prova sul campo DJI Osmo Nano: la piccola fotocamera alla prova ...
FUJIFILM X-T30 III, la nuova mirrorless compatta FUJIFILM X-T30 III, la nuova mirrorless compatta
Oracle AI World 2025: l'IA cambia tutto, a partire dai dati Oracle AI World 2025: l'IA cambia tutto, a parti...
Dallo spazioporto di Jiuquan decollerann...
Il Giappone un passo più vicino a...
Gli interferometri LIGO, Virgo e KAGRA h...
Kia PV5: è record di autonomia! I...
L'aeroplano supersonico ''silenzioso'' N...
Nissan: le batterie allo stato solido co...
NVIDIA cambia strategia? La GPU Feynman ...
Signal respinge le accuse dopo il down A...
Uragano Melissa in arrivo: la tempesta d...
8K o 4K? Ecco perché il tuo occhi...
Mercato auto europeo in crescita nei pri...
Addio SSD e RAM, benvenuti funghi: dagli...
TCL Q6C: tecnologia e design per un TV c...
Corsair MP700 PRO XT al debutto: un SSD ...
Apple Watch Ultra 2 in titanio con GPS +...
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: 23:12.


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