Problem mit sleep

papapete

Mitglied
Hallo Leute,

bin neu hier und versuche mich in JAVA. Habe ein USB-Experimentierinterface und möchte eine Oberfläche in Java schreiben. Soweit alles gut geklappt, ich kann die IO's einlesen bzw. beschreiben.
Nun möchte ich folgendes realisieren:
Wenn ich einen Button drücke, soll das Programm 10 sec. warten. In dieser Zeit soll es aber den Analogeingang ständig einlesen und den Wert in einem Feld Anzeigen. Erst wenn die Zeit um ist, soll der Wert auch "einfrieren". Wenn ich sleep verwende friert mir aber der gesamte Thread ein und nach den 10 sec. wird der Wert ausgelesen und geschrieben. Habe mal ein Bsp. dazu geschrieben.

T1 ist die Klasse wo das Interface angesprochen wird.

Java:
import javax.swing.*;
import java.awt.*;

import java.awt.event.*;

public class test extends javax.swing.JFrame
{
    private JButton button1;
    private JPanel panelButton;
    private JLabel anzeige;
    public T1 jv= new T1();

    public test()
    {
        super("Fenster");
        setLocation(300,300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout(5,5));
        button1 = new JButton("Button 1");
        panelButton = new JPanel(new GridLayout(3,1));
        panelButton.add(button1);
        addButtonListener(button1);
        anzeige = new JLabel("Button klicken");
        getContentPane().add(anzeige);
        getContentPane().add(BorderLayout.WEST, panelButton);
        pack();
        setVisible(true);

    }

    public static void main(String[] args)
    {
        test g = new test();
    }

    private void addButtonListener(JButton b)
    {
        b.addActionListener(new ActionListener() 
        { 
            public void actionPerformed(ActionEvent ae) 
            { 
                messung();
            }
        });
    }

    private void messung()
    {
      jv.OpenDevice(0);
      try {
      Thread.sleep(1000);
      anzeige.setText(String.valueOf(jv.ReadAnalogChannel(2)));
      jv.OutputAnalogChannel(2, jv.ReadAnalogChannel(2));
      jv.CloseDevice();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    
    }    
}

Kann mir da evtl. jemand weiterhelfen?

Danke schon mal im Voraus
 
Du rufst sleep() auf dem EDT aus, das führt dann dazu dass dein ganzes Programm einfriert. Solche IO Sachen musst du in nem eigenen Thread ausführen.
 
Habe ich auch schon versucht. Hatte nur den Erfolg, dass

Java:
jv.OutputAnalogChannel(2, jv.ReadAnalogChannel(2));

auf dem Interface funtioniert hat, die Werte aber nicht im Textfeld angezeigt wurden.
 
Ich versteh nicht ganz wie ich die Treads organisieren soll.

Das Interface-Objekt T1 soll ja nicht in den "Schlafmodus", soweit kein Problem. Das Hauptfenster aber auch nicht, da während der Wartezeit die Werte des Analogeingangs angezeigt werden sollen.
 
Ok... habs jetzt mal so umgebaut. Keine Ahnung ob es "elegant" ist aber es funktioniert zumindest teilweise.

Java:
import javax.swing.*;
import java.awt.*;

import java.awt.event.*;

public class test extends JFrame
{
    private JButton button1;
    private JPanel panelButton;
    private JLabel anzeige;
    private JLabel zeit;
    public T1 jv= new T1();
    public Thread th1;
    public Thread th2;
    

    public test()
    {
        super("Fenster");
        setLocation(300,300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout(5,5));
        button1 = new JButton("Button 1");
        panelButton = new JPanel(new GridLayout(3,1));
        panelButton.add(button1);
        addButtonListener(button1);
        anzeige = new JLabel("Button klicken");
        zeit = new JLabel("Zeit");
        getContentPane().add(zeit);
        getContentPane().add(anzeige);
        getContentPane().add(BorderLayout.WEST, panelButton);
        pack();
        setVisible(true);

    }

    public static void main(String[] args)
    {
        test g = new test();
    }

    private void addButtonListener(JButton b)
    {
        b.addActionListener(new ActionListener() 
        { 
            public void actionPerformed(ActionEvent ae) 
            { 
                messung();
            }
        });
    }
    public class c2 implements Runnable{
      public void run(){
        for (int i = 0; i < 10; i++) {
      try {
        Thread.sleep(1000);
        anzeige.setText(String.valueOf(i)+" sec");
        
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } 
      }
        jv.CloseDevice();
        th1.interrupt();
        th2.interrupt();
      }
    }
    
    public class c1 implements Runnable{
      public void run(){
        jv.OpenDevice(0);
        while (true){
          //anzeige.setText(String.valueOf(jv.ReadAnalogChannel(2)));
          jv.OutputAnalogChannel(2, jv.ReadAnalogChannel(2));
        }
      }
    }

    public void messung()
    {
    th1 = new Thread(new c1());
    th1.start();
    th2 = new Thread(new c2());
    th2.start();
    }  
    
}

allerdings bleibt das Prog nach dem Ablauf hängen.
 
Ein Thread "beendet" sich, sobald die run Methode abgeschlossen ist.
Um die Schleife in der run zu beenden könnte man z.B. ein Flag von aussen setzen.
 
Ok aber in der run() des 2-ten Threads hab ich doch
Java:
th1.interrupt();
        th2.interrupt();
warum werden die Threads dadurch nicht beendet?
 
Ok aber in der run() des 2-ten Threads hab ich doch
Java:
th1.interrupt();
        th2.interrupt();
warum werden die Threads dadurch nicht beendet?


Das geht so nicht. Angenommen Du hast eine boolsche Variable looping, die auf true gesetzt ist. Dann kann die while-Schleife mit while(looping) programmiert werden. Innerhalb der while-Schleife gibt es einen try/catch-Block, welches eine InterruptedException abfängt. Innerhalb dieses Blocks kann dann die boolsche Variable looping auf false gesetzt werden, die while-Schleife bricht dann ab und der Thread wird korrekt beendet.
 
Zuletzt bearbeitet:
Ahh ok jetzt bin ich etwas schlauer. Bekomme aber dabei:

Java:
boolean looping=true;
        while (looping){
        	try {
                jv.OutputAnalogChannel(2, jv.ReadAnalogChannel(2));
                
              } catch (InterruptedException e) {
				
			
                looping=false;
              } 
          //anzeige.setText(String.valueOf(jv.ReadAnalogChannel(2)));
          
        }

die Fehlermeldung dass der catch-Block nicht erreichbar ist.
Wenn ich eine andere while-Bedingung definiere (z.B. digitaler Eingang) dann funktioniert es.
 
Naja, hier läuft nichts, was eine InterruptedException werfen könnte ;-)
Du kannst z.B. das boolean Flag aus dem anderen Thread heraus auf false setzen.
 
die Fehlermeldung dass der catch-Block nicht erreichbar ist.

Es geht auch ohne boolsche Variable looping, hier ein Beispiel:

Code:
public class ThreadRunning extends Thread {
	public void run() {
		while (!isInterrupted()) {
			// do something
			try {
				Thread.sleep(0);
			} catch (InterruptedException e) {
				interrupt();
			}
		}
	}
}

Der Thread.sleep(0) ist wichtig, damit die InterruptedException abgefangen werden kann. Wird dieser Thread gestartet, wird mit der Methode interrupt() korrekt beendet.
 
Also ich bin ratlos... habs jetzt so versucht... es bleibt hängen.

Java:
import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

public class test extends JFrame
{
    private JButton button1;
    private JPanel panelButton;
    private JLabel anzeige;
    private JLabel zeit;
    public T1 jv= new T1();
    public Thread th1;
    public Thread th2;
    

    public test()
    {
        super("Fenster");
        setLocation(300,300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout(5,5));
        button1 = new JButton("Button 1");
        panelButton = new JPanel(new GridLayout(3,1));
        panelButton.add(button1);
        addButtonListener(button1);
        anzeige = new JLabel("Button klicken");
        zeit = new JLabel("Zeit");
        getContentPane().add(zeit);
        getContentPane().add(anzeige);
        getContentPane().add(BorderLayout.WEST, panelButton);
        pack();
        setVisible(true);

    }

    public static void main(String[] args)
    {
        test g = new test();
    }

    private void addButtonListener(JButton b)
    {
        b.addActionListener(new ActionListener() 
        { 
            public void actionPerformed(ActionEvent ae) 
            { 
                messung();
            }
        });
    }
    public class c2 extends Thread{
      public void run(){
        for (int i = 0; i <= 10; i++) {
      try {
        Thread.sleep(1000);
        //anzeige.setText(String.valueOf(i)+" sec");
        
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        interrupt();
      } 
      }
        jv.CloseDevice();
        th1.interrupt();
        th2.interrupt();
        
      }
    }
    
    public class c1 extends Thread{
      public void run(){
        jv.OpenDevice(0);
         while (true){
        	 jv.OutputAnalogChannel(2, jv.ReadAnalogChannel(2));
        	 anzeige.setText(String.valueOf(jv.ReadAnalogChannel(2)));
        	 if (isInterrupted()){
        		 break;}          
        }
      }
    }

    public void messung()
    {
    th1 = new Thread(new c1());
    th1.start();
    th2 = new Thread(new c2());
    th2.start();
    }  
    
}
 
Das Klassendesign ist sehr wirr: Th1 und Th2 werden innerhalb der Klasse test deklariert und gestarten um dann in der Klasse c2 unterbrochen zu werden?

Kannst Du bitte etwas genauer spezifizieren, was der Code tun soll?
 
Ja ist etwas wirr ich weiß...
th1 soll kontinuierlich den Analogwert auslesen und diesen im Textfeld anzeigen.
th2 soll 10 mal 1 sec stoppen (evtl. auch anzeigen 0-10 sec.) und dann beide Threads beenden.
 
Du startest die Threads c1 und c2 nie. Daher bringen die Interrupts nichts.

Probier es mal so:
[JAVA=85]public void messung()
{
th1 = new c1();
th1.start();
th2 = new c2();
th2.start();
}[/code]
 
hab ich gemacht... gleiches Problem. Das Prog läuft ab, bleibt dann aber hängen d.h. gibt den Button nicht wieder frei und lässt sich nicht schließen. Läuft dann noch ne weile und "verschwindet" von alleine. Hab auch versucht die Klassen c1 und c1 ausserhalb von der Klasse test zu deklarieren --> keine Besserung
 
OK der Fehler muss irgendwo im Objekt jv zu finden sein.
Habe mal das ganze mit dem Interface auskommentiert und eine Zufallszahl anzeigen lassen ---> funktioniert.
 
OK der Fehler muss irgendwo im Objekt jv zu finden sein.
Das kann schon sein.
Hier mal ein (meiner Meinung) etwas besser stukturierter Code - allerdings mit der Flag Lösung
Java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ChannelRead extends JFrame {
	private JButton button1;
	private JLabel anzeige;
	private JLabel zeit;
	private T1 jv = new T1();
	
	public static void main(String[] args) {
		new ChannelRead();
	}

	public ChannelRead() {
		super("Fenster");
		setBounds(0, 0, 300, 200);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		zeit = new JLabel("Zeit", JLabel.CENTER);
		add(zeit, BorderLayout.NORTH);
		button1 = new JButton("Start");
		add(button1, BorderLayout.SOUTH);
		anzeige = new JLabel("Button klicken");
		add(anzeige, BorderLayout.CENTER);
		setVisible(true);
		
		button1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				startMessung();
			}
		});
	}
	
	private volatile boolean loop = false;
	
	public void startMessung() {
		if (loop) //Wenn gerade eine Messung läuft
			return;
		
		loop = true;
		new Thread(new Runnable() {
			public void run() {
				jv.OpenDevice(0);
				while(loop) {
					jv.OutputAnalogChannel(2, jv.ReadAnalogChannel(2));
					anzeige.setText(String.valueOf(jv.ReadAnalogChannel(2)));
				}
				jv.CloseDevice();
				zeit.setText("Ende");
			}
		}).start();
		
		new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i <= 10; i++) {
					try {
						zeit.setText("" + i);
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				loop = false;
			}
		}).start();
	}
}
 
Vielen Vielen Dank... es funktioniert. Aber damit ich in Zukunft nicht ähnliche Fehler mache: Kann mir bitte jemand erklären wo genau mein Fehler war? Das mit dem loop hatte ich - auch wenn nicht so elegant - ja auch probiert.
 

Zurück
Oben