Visualizzazione dei risultati da 1 a 9 su 9
  1. #1
    Utente di HTML.it
    Registrato dal
    Jan 2014
    Messaggi
    305

    Problema con variabile volatile

    codice:
    public SWListaOperatori(ClienteDB cliente, FormListaClientiServer frame) {
            this.frameClienti = frame;
            this.cliente = cliente;
    
    
        }
    
    
        /**
         * Scarica tutti gli operatori , e ritorna una lista con tutti i nomi utente
         *
         * @return ArrayList conentente i nomi utente degli operatori
         * @throws Exception
         */
        @Override
        protected ArrayList<Object> doInBackground() throws Exception {
            ResultSet rs = Database.getInstance().viewTableContent(GestoreDatabase.Tabella.OPERATORE);
            ArrayList<Object> list = new ArrayList<>();
            while (rs.next()) {
                list.add(rs.getObject(1));
            }
            rs.getStatement().close();
            return list;
    
    
        }
    
    
        /**
         * Permette di effettuare il cambio di operatore attraverso l'interfaccia
         * grafica
         */
        @Override
        protected void done() {
            ArrayList<Object> list = null;
            try {
                list = this.get();
            } catch (InterruptedException | ExecutionException ex) {
                Logger.getLogger(SWListaOperatori.class.getName()).
                        log(Level.SEVERE, null, ex);
            }
            if (list != null && !list.isEmpty()) {
                final Object choice = JOptionPane.showInputDialog(null, "Seleziona Operatore", "Assegna Cliente:  " + cliente.getId_cliente() + " " + cliente.getNome() + " " + cliente.getCognome(),
                        JOptionPane.QUESTION_MESSAGE, null, list.toArray(), 0);
                if (choice != null) {
                    SWInviaAppuntamento swIA = new SWInviaAppuntamento((String) choice);
                    swIA.execute();
    
    
                }
    
    
            } else {
                JOptionPane.showMessageDialog(null, "Non ci sono altri operatori a cui assegnare");
            }
        }
    
    
        private class SWInviaAppuntamento extends SwingWorker<Boolean, Void> {
    
    
            private final String userOperatore;
            private volatile boolean aggiornato;
    
    
            public SWInviaAppuntamento(String choice) {
                this.userOperatore = choice;
                aggiornato = false;
            }
    
    
            @Override
            protected Boolean doInBackground() throws Exception {
                if (this.userOperatore != null) {
                    Operatore operatoreAttuale = Database.getInstance().getOperatoreClienteDB(cliente);
                    if (!operatoreAttuale.getLogin().getUsername().equalsIgnoreCase(this.userOperatore)) {
                        boolean appuntamentoDisponibile = !Database.getInstance().verificaDisponibilitaAppuntamento(userOperatore, cliente.getDataAppuntamento(), cliente.getOraAppuntamento());
                        if (!appuntamentoDisponibile) {
    
    
                            Thread thread = new Thread(new Runnable() {
    
    
                                @Override
                                public void run() {
    
    
                                    int scelta = JOptionPane.showConfirmDialog(frameClienti,
                                            "L'operatore a cui e' stato assegnato l'appuntamento\n"
                                            + "non e' disponibile per la data e l'ora indicata in quello "
                                            + "\nche gli si vuole assegnare" + "\nE' possibile comunque assegnarlo,"
                                            + "\ncambiando però prima la data dell'appuntamento\n Vuoi Procedere?");
                                    if (scelta == JOptionPane.OK_OPTION) {
                                        final FormSchedaCliente schedaCliente = new FormSchedaCliente(frameClienti, frameClienti.getModelTable(), cliente);
                                        try {
                                            final Operatore oldOperator = Database.getInstance().getOperatoreClienteDB(cliente);
                                            Database.getInstance().updateField(10, 1, Integer.toString(cliente.getId_cliente()), (String) userOperatore,
                                                    GestoreDatabase.Tabella.CLIENTE);
                                            schedaCliente.setup();
                                            schedaCliente.disableAppuntamentoOKButton();
                                            schedaCliente.disableAppuntamentoKOButton();
                                            schedaCliente.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                                     
                                            schedaCliente.addWindowListener(new WindowAdapter() {
                                               
                                                
                                                @Override
                                                public void windowClosed(WindowEvent evt) {
                                                    aggiornato=true;//la aggiorno quando si chiude la finestra
                                                    synchronized (schedaCliente) {
                                                        schedaCliente.notify();//e notifico la chiusura al thread
                                                    }
                                                }
    
    
                                                @Override
                                                public void windowClosing(WindowEvent evt) {
                                                    try {
                                                        aggiornato=false;
                                                        JOptionPane.showMessageDialog(schedaCliente, "Assegnazione Annullata");
                                                        Database.getInstance().updateField(10, 1, Integer.toString(cliente.getId_cliente()), oldOperator.getLogin().getUsername(),
                                                                GestoreDatabase.Tabella.CLIENTE);
                                                        synchronized (schedaCliente) {
                                                            schedaCliente.notify();//il thread si risveglia e termina
                                                        }
                                                    } catch (SQLException ex) {
                                                        Logger.getLogger(SWListaOperatori.class.getName()).log(Level.SEVERE, null, ex);
                                                    }
                                                }
    
    
                                            });
                                            schedaCliente.setRiprogrammaActionListener(new RiprogrammaAppuntamentoListener(schedaCliente));
                                            schedaCliente.setAppuntamentoKOActionListener(new AppuntamentoKOListener(schedaCliente));
                                            schedaCliente.setAppuntamentoOKActionListener(new AppuntamentoOkListener(schedaCliente));
                                            schedaCliente.setVisible(true);
                                             synchronized (schedaCliente) {
                                                
                                                 while (schedaCliente.isVisible()) {
                                                     schedaCliente.wait();
                                                }
                                            }
    
    
                                        } catch (ParseException | InterruptedException | SQLException | IOException ex) {
                                            Logger.getLogger(SWListaOperatori.class.getName()).log(Level.SEVERE, null, ex);
                                        }
    
    
                                    }
    
    
                                }
    
    
                            });
                            thread.start();
                            thread.join();//lui ritorna dal join , ma la variabile vale ancora false
                            System.out.println("fine join");
                        } else if (appuntamentoDisponibile) {
                            aggiornato = Database.getInstance().updateField(10, 1, Integer.toString(cliente.getId_cliente()), (String) this.userOperatore,
                                    GestoreDatabase.Tabella.CLIENTE);
                            InetAddress addr = ServerListener.getAddressByUsername(this.userOperatore);
                            if (addr != null) {
                                InformazioniAlClient assegnaAppuntamento = new InformazioniAlClient(cliente, addr, Operazioni.AGGIORNA_APPUNTAMENTO);
                                assegnaAppuntamento.inviaInfoAppuntamento();
                            }
                        }
                        
                        if (aggiornato) {
                            InetAddress addrOldOp = ServerListener.getAddressByUsername(operatoreAttuale.getLogin().getUsername());
                            //Comunico al vecchio operatore che l'appuntamento è stato assegnato ad altri
                            if (addrOldOp != null) {
                                InformazioniAlClient infoToOldOp = new InformazioniAlClient(cliente, addrOldOp, Operazioni.ASSEGNATO_ALTRO);
                                infoToOldOp.inviaInfoAppuntamento();
                            }
    
    
                        }
                    }else{
                        aggiornato=false;
                    }
    
    
                }else{
                    aggiornato=false;
                }
    
    
                return aggiornato;
    
    
            }
            
            
    
    
            @Override
            protected void done() {
                try {
                    boolean val = this.get();
                    if (val) {
                        JOptionPane.showMessageDialog(frameClienti, "Cliente Assegnato a "
                                + this.userOperatore, "Assegnazione avvenuta",
                                JOptionPane.INFORMATION_MESSAGE);
                    } else {
                        JOptionPane.showMessageDialog(frameClienti, "Cliente non assegnato! Errore!", "Assegnazione non avvenuta",
                                JOptionPane.ERROR_MESSAGE);
                        
                    }
                } catch (InterruptedException | ExecutionException ex) {
                    Logger.getLogger(SWListaOperatori.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
    
    
        }
    Nonostante la variabile aggiornato sia volatile, quando il thread ritorna dal join la variabile risulta ancora false !! Ho messo dei commenti sulla situazione dove si verifica il problema

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Voglio essere sincero e onesto: il tuo codice è parecchio "fumoso" e ci sono svariate cose che sono inappropriate e per niente belle.
    Il problema non è una variabile volatile ......
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Utente di HTML.it
    Registrato dal
    Jan 2014
    Messaggi
    305
    Quote Originariamente inviata da andbin Visualizza il messaggio
    Voglio essere sincero e onesto: il tuo codice è parecchio "fumoso" e ci sono svariate cose che sono inappropriate e per niente belle.
    Il problema non è una variabile volatile ......

    ti sarei grato se specificassi cosa non ti piace o non va

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da linux_r Visualizza il messaggio
    ti sarei grato se specificassi cosa non ti piace o non va
    Oh certo ... ma l'elenco è lungo (e non sarò sicuramente esaustivo al 100%):

    - il codice non è completo ma dai metodi si deduce che SWListaOperatori è uno SwingWorker. SWListaOperatori contiene una inner-class SWInviaAppuntamento che è di nuovo uno SwingWorker (di per sé tecnicamente nulla di sbagliato ma è perlomeno strano/inusuale). Nel doInBackground di SWInviaAppuntamento c'è una anonymous inner class per un Runnable. Nel suo run() ad un certo punto c'è una ulteriore anonymous inner-class per un WindowAdapter. Quando si arriva ad un tale livello di annidamento con pure tutti i vari blocchi if/try in mezzo, dovrebbe suonarti un campanello di allarme .... un grosso campanello ...

    - in questo codice usi di tutto e di più: da SwingWorker, ai thread, alla sincronizzazione con synchronized, all'uso di volatile, all'uso della condition-queue "intrinseca" (il wait/notify sugli oggetti). Dubito che quello sia l'unico modo per fare quello che volevi ma anche se fosse davvero tutto necessario, così è comunque un po' sparpagliato e fumoso.

    - nel primo doInBackground non si capisce assolutamente che cosa si ottiene. Cosa conterrà quel ArrayList<Object>? Che colonna (e di che tipo) prendi con getObject(1) ? Solo tu lo sai ....
    Manca di chiarezza.

    - sempre in questo doInBackground il close non viene fatto sempre. Se next() o getObject() lanciano SQLException, tu non chiudi nulla. Manca di correttezza nella gestione delle eccezioni.
    E anche se facessi tutto corretto con le eccezioni, tutta la logica di query ed estrazione dal result-set andrebbe fatta in una classe separata.

    - guardando le invocazioni sulla istanza di Database, sembrano un po' una accozzaglia di operazioni ben diverse. Evita di fare una classe "Database" che fa di tutto e di più. Avresti potuto/dovuto applicare almeno il pattern DAO, per risolvere anche quanto detto al punto precedente.

    - Database.getInstance().updateField(10, 1, Integer.toString(cliente.getId_cliente()), (String) userOperatore, GestoreDatabase.Tabella.CLIENTE);
    Non è un buon modo di fare un update di uno o più campi. Tra l'altro "sembra" un metodo molto generico/arbitrario e quindi poco comprensibile. Cosa sono ad esempio 10 e 1 ? Solo tu lo sai ....

    - nel run() del tuo thread vai ad accedere alla interfaccia utente. Non sei nel contesto del EDT, tutto quello che fai con JOptionPane, setVisible(true) ecc... è tutto inappropriato.

    - nel run() comunque c'è un mix di accesso a database, interfaccia grafica, wait/notify. Tutto potenzialmente molto dubbio (fumoso sicuramente).

    - fai un synchronized su schedaCliente che è un oggetto GUI. Per quanto ne so, non c'è nulla di intrinsecamente (e tecnicamente) errato nell'usare oggetti GUI come "lock". Ma personalmente io non lo farei mai nemmeno se mi pagate il doppio del mio stipendio ....

    E mi sono limitato solo alle cose più evidenti ....
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Utente di HTML.it
    Registrato dal
    Jan 2014
    Messaggi
    305
    Quote Originariamente inviata da andbin Visualizza il messaggio
    Database.getInstance().updateField(10, 1, Integer.toString(cliente.getId_cliente()), (String) userOperatore, GestoreDatabase.Tabella.CLIENTE);
    Non è un buon modo di fare un update di uno o più campi. Tra l'altro "sembra" un metodo molto generico/arbitrario e quindi poco comprensibile. Cosa sono ad esempio 10 e 1 ? Solo tu lo sai ....

    Per quanto riguarda la classe database al suo interno i metodi sono commentati e hanno la javadoc, comunque si è un metodo generico e a dire il vero non ci vedo nulla di male null'utilizzarlo.


    Quote Originariamente inviata da andbin Visualizza il messaggio

    - guardando le invocazioni sulla istanza di Database, sembrano un po' una accozzaglia di operazioni ben diverse. Evita di fare una classe "Database" che fa di tutto e di più. Avresti potuto/dovuto applicare almeno il pattern DAO, per risolvere anche quanto detto al punto precedente.


    grazie per questo consiglio , purtroppo è un corso introduttivo a java e non sapevo nemmeno l'esistenza di questo pattern, non è tra gli argomenti del corso , almeno adesso so che esiste

    Quote Originariamente inviata da andbin Visualizza il messaggio

    - il codice non è completo ma dai metodi si deduce che SWListaOperatori è uno SwingWorker. SWListaOperatori contiene una inner-class SWInviaAppuntamento che è di nuovo uno SwingWorker (di per sé tecnicamente nulla di sbagliato ma è perlomeno strano/inusuale). Nel doInBackground di SWInviaAppuntamento c'è una anonymous inner class per un Runnable. Nel suo run() ad un certo punto c'è una ulteriore anonymous inner-class per un WindowAdapter. Quando si arriva ad un tale livello di annidamento con pure tutti i vari blocchi if/try in mezzo, dovrebbe suonarti un campanello di allarme .... un grosso campanello ..

    Non mi pare di aver letto da nessuna parte che non si possano annidare classi oltre un certo livello, e' una regola?

    Quote Originariamente inviata da andbin Visualizza il messaggio

    sempre in questo doInBackground il close non viene fatto sempre. Se next() o getObject() lanciano SQLException, tu non chiudi nulla. Manca di correttezza nella gestione delle eccezioni.
    E anche se facessi tutto corretto con le eccezioni, tutta la logica di query ed estrazione dal result-set andrebbe fatta in una classe separata.


    mmmm su questo sono d'accordo con te dovrei farlo stesso nella classe database o creare una classe a parte?
    Quote Originariamente inviata da andbin Visualizza il messaggio

    - nel primo doInBackground non si capisce assolutamente che cosa si ottiene. Cosa conterrà quel ArrayList<Object>? Che colonna (e di che tipo) prendi con getObject(1) ? Solo tu lo sai ....
    Manca di chiarezza.
    Anche in questo caso il metodo è commentato e spiega cosa contiene quell'array di ritorno

    Comunque le critiche purchè costruttive sono sempre accettatissime
    Ultima modifica di linux_r; 13-07-2014 a 10:11

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da linux_r Visualizza il messaggio
    comunque si è un metodo generico e a dire il vero non ci vedo nulla di male null'utilizzarlo.
    No, non è comunque un "buon" modo.

    Quote Originariamente inviata da linux_r Visualizza il messaggio
    Non mi pare di aver letto da nessuna parte che non si possano annidare classi oltre un certo livello, e' una regola?
    Sì ... del "buon senso".

    Quote Originariamente inviata da linux_r Visualizza il messaggio
    Anche in questo caso il metodo è commentato e spiega cosa contiene quell'array di ritorno
    Ammetto che quando ho letto il tuo codice, mi sono concentrato sul codice ... e non sui commenti.
    Ma se sono nomi .... allora perchè "Object" ?
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  7. #7
    Utente di HTML.it
    Registrato dal
    Jan 2014
    Messaggi
    305
    perchè magari un giorno sarebbe potuto cambiare il campo del database , ho messo object per non dover poi modificare il codice

  8. #8
    Utente di HTML.it
    Registrato dal
    Jan 2014
    Messaggi
    305
    giacchè comuqnue l'argomento si è spostato sulla programmazione java vorrei chiederti una cosa. "uno stream è un flusso di dati, un oggetto dal quale si può leggere una sequenza di byte prende nome di input stream , mentre un oggetto nel quale si può scrivere una sequenza di byte prende nome di output stream o sink stream. Vengono detti nodi di stream i file , le memorie e pipe tra thread o processi. Source stream e sink stream sono entrambi dei node streams-."
    Cosa ne pensi di questa definizione ? la trovi corretta?

  9. #9
    Utente di HTML.it L'avatar di Alex'87
    Registrato dal
    Aug 2001
    residenza
    Verona
    Messaggi
    5,802
    Quote Originariamente inviata da linux_r Visualizza il messaggio
    perchè magari un giorno sarebbe potuto cambiare il campo del database , ho messo object per non dover poi modificare il codice
    Allora metti un generico T, no?
    SpringSource Certified Spring Professional | Pivotal Certified Enterprise Integration Specialist
    Di questo libro e degli altri (blog personale di recensioni libri) | ​NO M.P. TECNICI

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2026 vBulletin Solutions, Inc. All rights reserved.