Thread läßt sich nicht Abbrechen

Hallo Gemeinde,

ich habe ein Problem mit dem Abbrechen eines Thread mit Hilfe eines “Cancel”-Button.

Ich habe mir eine Klasse (ProgressDialog) erstellt die von JDialog abgeleitet ist und in dieser wird ein Fenster mit JProgressBar, einem Label und der besagte Cancel Button definiert.
Ein Objekt meiner Klasse (EncodeThread) die den Thread darstellt wird in ProgressDialog erzeugt. Wenn ich aber den Konvertierungsvorgang abrechen will, mit Hilfe des Cancel Button, passiert nichts.
Auch ein schließen des Dialog beendet den Thread nicht. Erst wenn ich das Hauptfenster, also das Programm schließe wird auch der Prozess beendet. Ich bekomme dann eine IllegalStateException im Thread EncodeThread.

Da es für mich auch das erstemal ist das ich mit Thread arbeite ist mein Latein nun am Ende, ich weiss nicht ob ich was falsch verstanden habe oder einfach nur einen blöden Fehler drin habe.
Vielleicht kann mir jemand von euch weiterhelfen bzw. mich auf den richtigen Pfad bringen.

Hier mal die zwei Klassen die meines erachtens nach die wichtigen sind.

ProgressDialog:

import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;

class ProgressDialog extends JDialog implements ActionListener
{
    private static JProgressBar pb = new JProgressBar(0, 100);
    private static JLabel label = new JLabel("Conversion is started, please wait...");
    
    private JButton cancelbutton;
    
    public ProgressDialog(File source, File target)
    {
        
        super();
        setSize(new Dimension(250,125));
        setLocationRelativeTo( null );
        setResizable( false );
        setTitle("Conversion");
        setModal( true );
        
        cancelbutton = new JButton("Cancel");
        cancelbutton.addActionListener( this );
        
        JPanel panel = new JPanel();
        panel.setBorder( BorderFactory.createEmptyBorder( 2, 4, 2, 4 ) );
        panel.setLayout(new GridLayout(3,1));
        panel.add(label);
        panel.add(pb);
        panel.add( cancelbutton );
        
        
        EncodeThread encode = new EncodeThread(source, target);
        encode.startEncoding();
        
        add(panel);
    }
    
    public static JLabel getLabel()
    {
        return label;
    }
    public static JProgressBar getProgressBar()
    {
        return pb;
    }

    @Override
    public void actionPerformed( ActionEvent evt )
    {
        if(evt.getSource() == cancelbutton)
        {
            EncodeThread.stopEncoding();
        }
        
    }
}

EncodeThread:

import it.sauronsoftware.jave.AudioAttributes;
import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.EncoderException;
import it.sauronsoftware.jave.EncodingAttributes;
import it.sauronsoftware.jave.InputFormatException;
import it.sauronsoftware.jave.VideoAttributes;
import it.sauronsoftware.jave.VideoSize;

import java.io.File;



class EncodeThread extends Thread
{
    private File source;
    private File target;
    private static Thread encodingthread; 
    
    public EncodeThread(File src, File targ)
    {
        source = src;
        target = targ;
    }
    
    public void startEncoding()
    {
        encodingthread = new Thread( this);
        encodingthread.setName("EncodingThread");
        encodingthread.start();
    }
    
    public static void stopEncoding()
    {
        encodingthread.interrupt(); 
    }
    
    @Override
    public void run() 
    {
        while(!isInterrupted())
        {
            try
            {
                startEncode();
            }
            catch ( InterruptedException e )
            {
                interrupt();
                System.err.println( e );
            }
        }
    }
    
    private void startEncode() throws InterruptedException
    { 
        AudioAttributes audio = new AudioAttributes();
        audio.setCodec("libmp3lame");
        audio.setBitRate( new Integer(64000) );
        audio.setChannels(new Integer(1));
        audio.setSamplingRate( new Integer( 22050) );
        
        VideoAttributes video = new VideoAttributes();
        video.setCodec("flv");
        video.setBitRate( new Integer(368640) );
        video.setFrameRate( new Integer(25) );
        video.setSize( new VideoSize(400, 300) );
        
        final EncodingAttributes attr = new EncodingAttributes();
        attr.setFormat("flv");
        attr.setAudioAttributes(audio);
        attr.setVideoAttributes(video);
        
        try
        {
            Encoder encoder = new Encoder();
            ProgressListener progresslistener= new ProgressListener();
            encoder.encode(source, target, attr, progresslistener); throw new InterruptedException();
        }
        catch ( IllegalArgumentException e )
        {
            System.err.println(e.getMessage());
        }
        catch ( InputFormatException e )
        {
            System.err.println(e.getMessage());
        }
        catch ( EncoderException e )
        {
            System.err.println(e.getMessage());
        }
    }
}

Niemals interrupt() anwenden!
Ich ändere Mal deine EncodeThread Klasse!
So müsste es funktionieren:

import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.EncoderException;
import it.sauronsoftware.jave.EncodingAttributes;
import it.sauronsoftware.jave.InputFormatException;
import it.sauronsoftware.jave.VideoAttributes;
import it.sauronsoftware.jave.VideoSize;
 
import java.io.File;
 
 
 
class EncodeThread extends Thread
{
    private File source;
    private File target;
    private static Thread encodingthread;
    private run_Thread_run = true;
   
    public EncodeThread(File src, File targ)
    {
        source = src;
        target = targ;
    }
   
    public void startEncoding()
    {
        encodingthread = new Thread( this);
        encodingthread.setName("EncodingThread");
        encodingthread.start();
    }
   
    public static void stopEncoding()
    {
        run_Thread_run = false;
    }
   
    @Override
    public void run()
    {
        while(run_Thread_run)
        {
            try
            {
                startEncode();
            }
            catch ( InterruptedException e )
            {
                interrupt();
                System.err.println( e );
            }
        }
    }
   
    private void startEncode() throws InterruptedException
    {
        AudioAttributes audio = new AudioAttributes();
        audio.setCodec("libmp3lame");
        audio.setBitRate( new Integer(64000) );
        audio.setChannels(new Integer(1));
        audio.setSamplingRate( new Integer( 22050) );
       
        VideoAttributes video = new VideoAttributes();
        video.setCodec("flv");
        video.setBitRate( new Integer(368640) );
        video.setFrameRate( new Integer(25) );
        video.setSize( new VideoSize(400, 300) );
       
        final EncodingAttributes attr = new EncodingAttributes();
        attr.setFormat("flv");
        attr.setAudioAttributes(audio);
        attr.setVideoAttributes(video);
       
        try
        {
            Encoder encoder = new Encoder();
            ProgressListener progresslistener= new ProgressListener();
            encoder.encode(source, target, attr, progresslistener); throw new InterruptedException();
        }
        catch ( IllegalArgumentException e )
        {
            System.err.println(e.getMessage());
        }
        catch ( InputFormatException e )
        {
            System.err.println(e.getMessage());
        }
        catch ( EncoderException e )
        {
            System.err.println(e.getMessage());
        }
    }
}```

Beim ersten Blick auf den source code der sauronsoftware-Lib schaut es aus, als würde die eigentliche Arbeit dort von einer ffmpeg-EXE gemacht, die mit Runtime#exec gestartet wird. Das ganze hat im Zweifelsfall mit Java also nichts zu tun. Spontan würde ich sagen, dass man da schlicht nichts machen kann, aber vielleicht findet jemand was, wenn er sich das ganze genauer ansieht…

EDIT @IDC Zu interrupt was neulich was in http://forum.byte-welt.net/threads/10319-InterruptedException?p=67457&viewfull=1#post67457

Vielen Dank für die schnellen Antworten, das mit dem ändern der EncodeThread Klasse führte nicht zum Erfolg. Dazu aber gleich ne Frage, wieso soll ich niemals interrupt() verwenden. In der Dokumentation wird doch aber nur mit interrupt() gearbeitet. Soweit ich das verstanden haben setzt doch interrupt das Flag, dass der Thread unterbrochen werden soll. Mit isInterupted() kann ich dann doch das Flag abfragen und da isInterrupted() das Flag wieder löscht muss im catch{} das Flag nochmal erneut gesetzt werden.
@Marco13
Ja das ist richtig, die eigentliche Konvertierung macht ffmpeg-EXE also sollte ich mir den Code dahingehend nochmal genauer ansehen ob ich da was machen kann bzw. was finde wo man ansetzen kann.
Denn es wäre ja blöd ne Konvertierung zu starten die man nicht wieder abbrechen kann.

Hm. Diese verwöhnten Java-User heutzutage. Zu meiner Zeit konnte man alles noch mit STRG+C abbrechen :smiley: Der einzige Ansatz, der mir spontan einfallen würde, wäre, sich irgendwie (notfalls mit Reflection) zu dem FFMPegExecutor durchzuhangeln, und auf dem dann „destroy()“ aufzurufen. Allgemein ist das etwas diffizil (Websuchen!, z.B. http://stackoverflow.com/questions/6356340/killing-a-process-using-java ), aber vielleicht einen Versuch wert…

Ich habe absolut nichts gegen weiße Schrift auf schwarzem Hintergrund, spar ich mir die Zeit die ich damit verschwende die Maus hin und her zu schupsen. Naja, anderes Thema…
Es gibt ja in der lib eine Klasse die ProcessKiller heißt. Diese Killt wahrscheinlich den ffmpeg Process, ich habe die aber nicht verwendet da sie eben destroy() verwendet und destroy() ist ja wie ich es in der Doku gelesen habe als Deprecated gekennzeichnet.

*** Edit ***

Ich habe jetzt noch mal ein wenig versucht und getan aber leider hat nichts dazu geführt das ich den Prozess so beenden kann wie ic es gern gehabt hätte.
Das Abbrechen des Prozesses scheint mir von aussen nicht möglich zu sein, zumindest sind die relevanten Klassen nicht importierbar da die sichtbarkeit eingeschränkt ist.

Ich habe mich also nun für die Holzhammer-Methode entschieden.
Mir ist bewust das ich somit die Plattformunabhängigkeit aufgegeben habe, aber da das Programm nur bei einer Person und auch nur auf einem Windows Rechner laufen wird, kann ich damit erst einmal leben.

    {
        try
        {
            Runtime.getRuntime().exec("taskkill /F /IM ffmpeg.exe");
        }
        catch ( IOException e )
        {
            System.err.println( e );
        }
    }```

Solange etwas eine .exe aufruft, scheint es mir eh plattformabhängig zu sein.

stimmt… daran hab ich gar nicht gedacht.
Manchmal sieht man den Wald voller Bäume nicht, hätte ich mir wieder auch einige Tipparbeit ersparen können.