Visualizzazione dei risultati da 1 a 6 su 6

Discussione: Multithreading

  1. #1

    Multithreading

    Ciao a tutti! avrei una domanda sul Multithreading molto semplice:
    Ho scritto il mio programma: questo si compone di un thread principale (la GUI) e quando voglio eseguire determinati calcoli genero thread secondari che quando hanno finito riempiono il thread principale. Vorrei evitare che i processi secondari non si sovrappongano e mandino in crash il programma perché due o più thread stanno cercando di accedere alle risorse del thread principale (GUI).

    Grazie!

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Lory1990 Visualizza il messaggio
    Ho scritto il mio programma: questo si compone di un thread principale (la GUI) e quando voglio eseguire determinati calcoli genero thread secondari che quando hanno finito riempiono il thread principale. Vorrei evitare che i processi secondari non si sovrappongano e mandino in crash il programma perché due o più thread stanno cercando di accedere alle risorse del thread principale (GUI).
    Il EDT, Event Dispatch Thread che gestisce la interfaccia utente, giustamente non va mai tenuto "impegnato" per troppo tempo con del proprio codice, quindi per operazioni "lunghe" serve un thread separato.
    Se un altro thread deve accedere alla interfaccia utente, deve far "passare" la esecuzione di questi accessi/aggiornamenti nel EDT (il classico invokeLater o invokeAndWait in casi più rari).
    Se invece un altro thread deve accedere a model, strutture dati, ecc... che sono anche usati dal EDT (o da altri thread), ci deve essere una sincronizzazione esplicita che garantisca la "mutua esclusione" ma sopratutto la "visibilità" delle modifiche.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Allora penso si dovrebbe implementare una sincronizzazione "manuale" in quanto durante i calcoli sulla GUI si aggiorna una JProgressBar e alla fine si riversano tutti i dati dentro la GUI. Come si implementa questo tenendo conto che non so quanti thread verranno aperti?

  4. #4
    Io avrei fatto un piccolo codice di prova che qui posto:

    codice:
    
    package MultiTH;
    
    
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.swing.JProgressBar;
    
    
    public class Interface extends javax.swing.JFrame {
    
    
        /**
         * Creates new form Interface
         */
        public Interface() {
            initComponents();
            this.setVisible(true);
        }
    
    
        /**
         * This method is called from within the constructor to initialize the form.
         * WARNING: Do NOT modify this code. The content of this method is always
         * regenerated by the Form Editor.
         */
        @SuppressWarnings("unchecked")
        // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
        private void initComponents() {
    
    
            BarPanel = new javax.swing.JPanel();
            jLabel1 = new javax.swing.JLabel();
            jButton1 = new javax.swing.JButton();
    
    
            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    
    
            BarPanel.setBackground(new java.awt.Color(255, 255, 204));
    
    
            jLabel1.setText("jLabel1");
            BarPanel.add(jLabel1);
    
    
            jButton1.setText("OK");
            jButton1.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    jButton1ActionPerformed(evt);
                }
            });
    
    
            javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
            getContentPane().setLayout(layout);
            layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addContainerGap()
                    .addComponent(BarPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 327, Short.MAX_VALUE)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(jButton1)
                    .addContainerGap())
            );
            layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addContainerGap()
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                            .addComponent(jButton1)
                            .addGap(0, 0, Short.MAX_VALUE))
                        .addComponent(BarPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE))
                    .addContainerGap())
            );
    
    
            pack();
        }// </editor-fold>                        
    
    
        private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
               MultiThreading();
        }                                        
    
    
        /**
         * @param args the command line arguments
         */
        public static void main(String args[]) {
            /* Set the Nimbus look and feel */
            //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
            /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
             * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
             */
            try {
                for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                    if ("Nimbus".equals(info.getName())) {
                        javax.swing.UIManager.setLookAndFeel(info.getClassName());
                        break;
                    }
                }
            } catch (ClassNotFoundException ex) {
                java.util.logging.Logger.getLogger(Interface.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (InstantiationException ex) {
                java.util.logging.Logger.getLogger(Interface.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                java.util.logging.Logger.getLogger(Interface.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (javax.swing.UnsupportedLookAndFeelException ex) {
                java.util.logging.Logger.getLogger(Interface.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            }
            //</editor-fold>
    
    
            /* Create and display the form */
            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    new Interface().setVisible(true);
                }
            });
        }
        // Variables declaration - do not modify                     
        private javax.swing.JPanel BarPanel;
        private javax.swing.JButton jButton1;
        private javax.swing.JLabel jLabel1;
        // End of variables declaration                   
    
    
        private void MultiThreading() {
            CalculateA A = new CalculateA();
            CalculateB B = new CalculateB();
            Thread tA = new Thread(A);
            tA.setPriority(10);
            tA.start();
            Thread tB = new Thread(B);
            tB.setPriority(10);
            tB.start();
        }
        
        private class CalculateA implements Runnable{
            @Override
            public void run() {
                JProgressBar A = new JProgressBar();
                A.setMaximum(200);
                BarPanel.add(A);
                BarPanel.revalidate();
                for(int i=0;i<201;i++){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException ex) {}
                    System.out.println("Value A: " + i);
                    synchronized(this){
                        A.setValue(i);
                        A.setString(String.valueOf(i));
                    }
                }
                synchronized(this){
                    BarPanel.remove(A);
                    BarPanel.revalidate();
                    BarPanel.repaint();
                }
            }
            
        }
        private class CalculateB implements Runnable{
            @Override
            public void run() {
                JProgressBar A = new JProgressBar();
                A.setMaximum(500);
                BarPanel.add(A);
                BarPanel.revalidate();
                for(int i=0;i<501;i++){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException ex) {}
    
    
                    System.out.println("Value B: " + i);
                    synchronized(this){
                        A.setValue(i);
                    }
                }
                synchronized(this){
                    BarPanel.remove(A);
                    BarPanel.revalidate();
                    BarPanel.repaint();
                }
    
    
            }
            
        }
    }
    Il codice simula due processi che riempiono due jprogressbar e accedono al thread della GUI tramite synchronized, ho fatto giusto?

  5. #5
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Lory1990 Visualizza il messaggio
    Il codice simula due processi che riempiono due jprogressbar e accedono al thread della GUI tramite synchronized, ho fatto giusto?
    No purtroppo. Lo ripeto: l'accesso alla interfaccia utente va fatto "passare" nel EDT (invokeLater/invokeAndWait), non basta un synchronized. Salvo casi, ben documentati e noti, in cui certi metodi della GUI sono "thread-safe". Ma sono davvero pochi.

    Inoltre sempre nei tuoi Runnable hai creato il JProgressBar. Idem è sbagliato, va fatto nel EDT.

    E ancora, hai usato synchronized(this) che di per sé è tecnicamente corretto ma non è appropriato. Se vuoi che un thread A possa modificare uno "stato" di qualcosa in modo che poi un thread B possa leggerlo correttamente, devi sì usare la sincronizzazione (se non è già implicita es. in qualche struttura dati) ma sopratutto sia A che B devono usare lo stesso oggetto di lock.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  6. #6
    Allora intanto mi sono spiegato sicuramente male ogni volta che lancio un calcolo inserisco in un pannello dedicato una nuova progress bar che alla fine del processo viene rimossa e questo devo farlo dai thread secondari penso...
    poi per quanto riguarda invokeLater/invokeAndWait penso di aver capito che devo modificare le parti con synchronized in

    codice:
    javax.swing.SwingUtilities.invokeLater(new Runnable() {                @Override
                    public void run() {
                        BarPanel.remove(A);
                        BarPanel.revalidate();
                        BarPanel.repaint();
                    }
    
                });


Tag per questa discussione

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 © 2025 vBulletin Solutions, Inc. All rights reserved.