Problem współbieżności i synchronizacji w klasie testowej

0

Witam,
Pomogliście ostatnim razem, teraz też nie wiem jak coś zrobić. Próbuję już 2 dzień i nic nie pomaga :/
Mam nadzieję ,że mogę na was liczyć :)

Do rzeczy:

Moja klasa testowa MyPanel:

package my;

import java.awt.Graphics;



public class MyPanel extends javax.swing.JPanel implements Runnable {
    
    boolean draw = false;
    
    Thread t;
    int x;
    int y;
    int counter = 0;
    
    
    public synchronized void getValue(boolean TrueOrFalse){
            draw = TrueOrFalse;
            notify();
    }
    

    
    @Override
	public void addNotify() {
		super.addNotify();
		t = new Thread(this);
		t.start();
	}
    
    @Override
    public synchronized void run(){
        do{
            
            try {
         while(!draw)
           wait();
       } catch (InterruptedException exc){}
            
            repaint();
            counter++;
            x = 0 + (int)(Math.random()*50); 
            y = 0 + (int)(Math.random()*50);
            
            try {
                Thread.sleep(300);
                } catch(InterruptedException ex) {
                Thread.currentThread().interrupt();
                }
                }while(true);
            }
        
    
    
        
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        //doDrawing(g);
        //g.drawLine(x, y, x, y); 
        g.fillRect(x, y, 10, 10);
    }
    
}

W głównej klasie programu usiłuję wywołać zmianę zmiennej "draw" z klasy MyPanel za pośrednictwem metody getValue.

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        jPanel1.getValue(true);
    }                          

Niestety, kliknięcie przycisku powoduje następujący komunikat błędu:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at my.JPanel_Thread.jButton1ActionPerformed(JPanel_Thread.java:64)
at my.JPanel_Thread.access$000(JPanel_Thread.java:4)
at my.JPanel_Thread$1.actionPerformed(JPanel_Thread.java:35)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2341)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6505)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
at java.awt.Component.processEvent(Component.java:6270)
at java.awt.Container.processEvent(Container.java:2229)
at java.awt.Component.dispatchEventImpl(Component.java:4861)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4492)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
at java.awt.Container.dispatchEventImpl(Container.java:2273)
at java.awt.Window.dispatchEventImpl(Window.java:2719)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:735)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:694)
at java.awt.EventQueue$3.run(EventQueue.java:692)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:708)
at java.awt.EventQueue$4.run(EventQueue.java:706)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:705)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

Chciałem dodać ,że jeśli zmienna "draw" w MyPanel zostanie domyślnie ustawiona na "true" to odtwarza się animacja zgodnie z moją intencją. Chciałem mieć jednak możliwość zatrzymywania i puszczania animacji dalej a w przyszłości także zmianę parametrów.

Niestety powyższy błąd uniemożliwia mi to :/
Proszę, powiedzcie mi co robię źle.

Pozdrawiam

ps. Java uczę się sam od około 2-3tyg i niestety nie mam dostępu do wykwalifikowanej w Java kadry. (na mojej uczelni nie ma zajęć z Java) :(

1

Zakładam, że zanim wywołujesz tą swoją metodę getValue(boolean value), to gdzieś tam w klasie "głównej" utworzyłeś obiekt klasy MyPanel i wywołałeś metodę addNotify()?

W ogóle btw ledwo widzę na oczy ze zmęczenia, ale staraj się definiować na początku swoich klas, w których "coś się dzieje", przejrzyste konstruktory. M. in. w konstruktorze umieszczałby wywołanie start() dla obiektu Thread. Naskrobałem Ci drobne dwie klasy korzystające z "flagi" do zawieszania i wznawiania wątku. Looknij sobie, może coś Ci się rozjaśni. Jak dalej będzie problem, to pisz. Postaramy się dojść "o so hosi". Btw zapodaj kod "głównej klasy".

/*
 * KLASA DEFINIUJĄCA WĄTEK
 */
public class NowyWątek implements Runnable {

     /*
      * DEKLARACJA ZMIENNYCH SKŁADOWYCH
      */
     private String nazwa;
     private boolean flaga;
     Thread t;
     
     /*
      * JEDNOARGUMENTOWY KONSTRUKTOR
      */
     NowyWątek(String nazwaWątku) {
          nazwa = nazwaWątku;
          t = new Thread(this, nazwa);
          System.out.println("Nowy wątek: " + t);
          flaga = false;
          t.start();
     }
     
     /*
      * DEFINICJA METODY RUN()
      */
     public void run() {
          try {
               for (int i = 15; i > 0; i--) {
                    System.out.println(nazwa + ": " + i);
                    Thread.sleep(800);
                    synchronized (this) {
                         while (flaga) {
                              wait();
                         }
                    }
               }
          } catch (InterruptedException e) {
               System.out.println(nazwa + " został przerwany." + '\n' + e);
          }
          System.out.println("Wyjście z wątku " + nazwa);
     }
     
     /*
      * METODA 'USYPIAJĄCA' WĄTEK
      */
     synchronized void uśpij() {
          flaga = true;
     }
     
     /*
      * METODA 'BUDZĄCA' WĄTEK
      */
     synchronized void obudź() {
          flaga = false;
          notify();
     }
}

/*
 * KLASA GŁÓWNA
 */
public class Demo {

     public static void main(String args[]) {
          
          /*
           * TWORZENIE DWÓCH EGZEMPLARZY KLASY 'NOWY WĄTEK'
           */
          NowyWątek w1 = new NowyWątek("Jeden");
          NowyWątek w2 = new NowyWątek("Dwa");
          
          /*
           * ZABAWA WĄTKAMI I METODAMI
           */
          try {
               Thread.sleep(4000);
               
               w1.uśpij();
               System.out.println("Zawieszenie wątku nr Jeden");
               
               Thread.sleep(4000);
               
               w1.obudź();
               System.out.println("Wznowienie wątku nr Jeden");
               
               w2.uśpij();
               System.out.println("Zawieszenie wątku nr Dwa");
               
               Thread.sleep(4000);
               
               w2.obudź();
               System.out.println("Wznowienie wątku nr Dwa");
               
          } catch (InterruptedException e) {
               System.out.println("Przerwanie wątku głównego");
          }

          /*
           * WYWOŁANIE METODY JOIN:
           * Wątek główny oczekuje na zakończenie pracy wątków 'w1' oraz 'w2'.
           */
          try {
               System.out.println("Oczekiwanie na zakończenie wątków");
               w1.t.join();
               w2.t.join();
               
          } catch (InterruptedException e) {
               System.out.println("Przerwanie wątku głównego");
          }
          System.out.println("Koniec wątku głównego");
     }
}

Pamiętaj, że w klasie Demo prócz wątków 'w1' oraz 'w2' wykonywany jest również tzw. wątek główny http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html

Pozdrawiam :)

2

Typowa przyczyna błędu

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
u początkujących, to brak tworzenia obiektu. Odpowiednia zmienna jest zadeklarowana (w przeciwnym wypadku awanturowałby się kompilator), ale brak instrukcji

zmienna = new PewnaKlasa();

A dokładniej błąd wygląda tak:

//deklaracja pola
PewnaKlasa zmienna;
//a potem wewnątrz konstruktora lub w ciele metody
PewnaKlasa zmienna = new PewnaKlasa();

Powstała zmienna lokalna o nazwie i typie identycznym z polem klasy. Odwołanie do zmienna w innej metodzie będzie odwołaniem do pola w klasie, które jest nadal nullem.

0

Nowy problem :<
Błąd który zgłaszało zniknął (co zresztą napisałem w komentarzu do posta bogdans) ale... pomimo ,że wątek teraz startuje to nie jest w stanie go zatrzymać (ani wznowić jeśli wystartuje z pozycji wstrzymanej)

Klasa główna:

package my;

public class JPanel_Thread extends javax.swing.JFrame {

    public JPanel_Thread() {
        initComponents();
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        javax.swing.JPanel jPanel1 = new MyPanel("");
        jButton1 = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setPreferredSize(null);
        setResizable(false);
        addContainerListener(new java.awt.event.ContainerAdapter() {
            public void componentAdded(java.awt.event.ContainerEvent evt) {
                formComponentAdded(evt);
            }
        });

        jPanel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
        jPanel1.setPreferredSize(new java.awt.Dimension(60, 60));

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 63, Short.MAX_VALUE)
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 58, Short.MAX_VALUE)
        );

        jButton1.setText("START");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jButton2.setText("STOP");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(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(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(jButton1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jButton2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jButton1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jButton2)))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>                        

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        jPanel1.WakeUp();
    }                                        

    private void formComponentAdded(java.awt.event.ContainerEvent evt) {                                    
        // TODO add your handling code here:
    }                                   

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        jPanel1.GoSleep();
    }                                        

    public static void main(String args[]) {      
    
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new JPanel_Thread().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify                     
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    // End of variables declaration                   
    private my.MyPanel jPanel1 = new my.MyPanel("");
}

Klasa MyPanel (przerobiona na wzór podany przez Gjorni):

package my;

import java.awt.Graphics;
import java.util.logging.Level;
import java.util.logging.Logger;



public class MyPanel extends javax.swing.JPanel implements Runnable {
    
    boolean draw = true;
    
    Thread t;
    int x;
    int y;
    int counter = 0;
    
        MyPanel(String title){
		t = new Thread(this, title);
		t.start();
	}
    
    
    synchronized void WakeUp(){
        draw = true;
       this.notify();
    }
    
    synchronized void GoSleep(){
    draw = false;
}
    
    @Override
    public void run(){
        try {
        while(true){
            
                synchronized(this){
                if(!draw){
                    this.wait();
                        }
        }
            repaint();
            counter++;
            x = 0 + (int)(Math.random()*50); 
            y = 0 + (int)(Math.random()*50);
            
            try {
                Thread.sleep(50);
                } catch(InterruptedException ex) {
                Thread.currentThread().interrupt();
                }
                }
        } catch (InterruptedException ex) {
                 Logger.getLogger(MyPanel.class.getName()).log(Level.SEVERE, null, ex);
             }
            }
        
            
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g); 
        g.fillRect(x, y, 10, 10);
    }
    
}

"Pracuję" w NetBeans stąd lekka sieczka w kodzie (z drugiej strony w drugim projekcie który jest docelowym jest sporo GUI i do niego potem przerzucę zdobyte doświadczenia...).

Mam nadzieję ,że w końcu dowiem się co robię źle.
Chciałem dodać ,że to co dzieje się w kodzie podanym w pierwszej odpowiedzi rozumiem.
Nie rozumiem czemu mój kod nie reaguje. Zakładam jakieś debilne niedopatrzenie :/

Pozdrawiam Serdecznie

ps. z góry dzięki za wszelką okazaną pomoc :)
Pomogliście już obaj baaaardzo dużo :)

--------[edit]-----------------
W programie istnieją 2 instancje (byty ?) tego samego wątku, MyPanel.
Nie wiem jeszcze jak się tego pozbyć. Help :D

Ale jest progres...


Dobra, podstawowym problemem jest ochrona Netbeans części kodu.
Nie umiem się dobrać do tego tak żeby całość móc przerobić absolutnie po swojemu.
Czy ktoś jest w stanie mi pomóc i wyjaśnić ?

Zwykłe Custumize Code nie wystarcza :/


K@#$% ja @#$%^ znalazłem. Przyczyną jest sam NetBeans.
Żeby projekt działał tak jak chcę muszę zmienić linijkę generowaną przez GUI Designer przy każdej zmianie... i nie da się nic z tym zrobić. FUCK.

Czas na migrację do Eclipse... :/

1 użytkowników online, w tym zalogowanych: 0, gości: 1