Kilka wątków a Swing

0

Witam, mam pewien problem. Tworzę GUI do monitorowania sieci. GUI składa się z JFrame(NodeMonitor), w którym umieszczone są JTree, oraz JTable. JTree zawiera zestaw węzłów, dla których mają być wyświetlane dane sieciowe w tabeli. I teraz pojawia się mój problem. Poza NodeMonitor, stworzona jest klasa SnmpFactory, która tworzy dla każdego węzła wątki zaimplementowane w klasie SnmpInformer. SNMPInformer pobiera odpowiednie dane z sieci i odpala metodę klasy NodeMonitor celem umieszczenia w kontenerze aktualnych danych. Bez GUI wszystko gra i buczy, na konsoli wyświetlane są poprawnie wszystkie dane, ale mam problem z odzwierciedleniem tych danych w tabeli dla odpowiedniego węzła.

NodeMonitor wygląda następująco:

public class NodeMonitor extends javax.swing.JFrame implements TreeSelectionListener {

    /** Creates new form NodeMonitor */
    public NodeMonitor() {
        initComponents();
        try {
            //Odczyt konfiguracji dotyczacych wezlow z pliku i umieszczenie w drzewie...


           //A nastepnie tworzymy obiekt SNMPFactory
        SnmpFactory sf = new SnmpFactory(this);
          //Zaczynamy pobieranie danych z sieci
        sf.startReceiving();
        jTree1.setSelectionRow(1);
        jTree1.addTreeSelectionListener(this);
    }
    
    public void setSnmpInfo(String nodeName, Hashtable<String,ArrayList<String>> snmpInfo_){

        //Metoda wywolywana przez watek, ktora umieszcza w kontenerze snmpInfo aktualne dane sieciowe
        snmpInfo.put(nodeName, (Hashtable<String,ArrayList<String>>)snmpInfo_.clone());

        //Pobieramy wybrany wezel drzewa i wyswietlamy jego zaktualizowane wartosci
        DefaultMutableTreeNode node = (DefaultMutableTreeNode)jTree1.getLastSelectedPathComponent();
        paintSelectedNodeInfo(node.toString());
     }

     public void valueChanged(TreeSelectionEvent arg0) {

        //W przypadku wybrania innego wezla, zaladowanie do tabeli jego danych
        DefaultMutableTreeNode node = (DefaultMutableTreeNode)jTree1.getLastSelectedPathComponent();
        paintSelectedNodeInfo(node.toString());
    }

SnmpFactory wygląda w ten sposób:

public class SnmpFactory {
    NodeMonitor nm;

    public SnmpFactory(NodeMonitor nm_){
        nm = nm_;
    }

    public void startReceiving(){
        try {
            //Wczytywanie konfiguracji wezlow z pliku..
            BufferedReader br = new BufferedReader(new FileReader("nodeMonitor1.cfg"));
            
            //Dopoki odczytujemy nowe wezly, tworzymy i odpalamy dla kazdego nowy watek
            while((pom = br.readLine()) != null){
                    SnmpInformer snmpInformer = new SnmpInformer(...    this.nm);
                    Thread runner = new Thread(snmpInformer);
                    runner.start();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Natomiast klasa wątku SnmpInformer wygląda następująco:

public class SnmpInformer extends Thread {
public void run() {
        int iteration = 0;
        while (true) {
            try {
                SNMPv1CommunicationInterface comInterface = new SNMPv1CommunicationInterface(version, hostAddress, community);
                this.initParams(comInterface);
                //w metodzie initParams() wywoływana jest poniższa metoda, która wysyla do kontenera NodeMonitor odpowiednie dane
                this.nm.setSnmpInfo(hostAddress.getHostName(), attribs);

                this.sleep(30000);
                iteration++;
                System.out.flush();
            } catch (Exception ee) {
                ee.printStackTrace();
            }       
    }
}

}

Po starcie programu uruchamiany jest JFrame NodeMonitor. Odczytuje z pliku cfg, z jakimi węzłami będzie miał do czynienia i wrzuca do JTree. Chwilę później tworzony jest obiekt SnmpFactory, który także z pliku odczytuje nazwy węzłów i tworzy dla każdego z nich oddzielny wątek. Każdy wątek po starcie zaczyna pobieranie z sieci odpowiednich danych, a następnie wywołuje metodę nm.setSnmpInfo(), która ustawia wartości w kontenerze klasy NodeMonitor. I teraz pojawia się problem: Po ustawieniu wartości tabeli dla aktualnie zaznaczonego węzła i zaśnięciu, cała tabela znika. To samo dzieje się przy przełączaniu węzłów w JTree. W debugu to to nawet działa, ale ze względu na trudności w debugowaniu programów z wątkami, nie mogłem za bardzo dojść o co chodzi. Jedyne co zauważyłem, to to, że przy zawieszeniu jednego wątka w debugu na breakpoincie, wszystkie tabele są widoczne, a przełączanie między węzłami działa. Czy ktoś ma może wie dlaczego tak się dzieje i jakie są sposoby rozwiązania mojego problemu?

Z góry dziękuję za odpowiedź i pozdrawiam,
kashinho

0

Swing jest jednowątkowy. W związku z tym zawsze, ale to zawsze do wywołań jakichkolwiek metod dla obiektów wywodzących się od klas Swinga używasz metod SwingUtilities.invokeLater() lub SwingUtilities.invokeAndWait(). Pierwsza jest asynchroniczna, a druga synchroniczna.
Musisz takie podejście stosować konsekwentnie. Nie możesz wołać bezpośrednio metod Swinga z różnych wątków bo wtedy powodujesz deadlocki, niszczenie danych i różne dziwne efekty. Czyli to co masz.

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