|
You last visited: Today at 02:25
Advertisement
Threads managen / Schleife fortsetzen, wenn Thread beendet
Discussion on Threads managen / Schleife fortsetzen, wenn Thread beendet within the Java forum part of the Coders Den category.
02/01/2015, 20:15
|
#1
|
elite*gold: 0
Join Date: Mar 2013
Posts: 3,184
Received Thanks: 1,317
|
Threads managen / Schleife fortsetzen, wenn Thread beendet
Hallo zusammen,
mein Problem ist folgendes:
Ich habe in einer ForEach-Schleife 3 Threads, die alle gleichzeitig ausgeführt werden müssen, allerdings auch jeweils nur diese 3 gleichzeitig. In der Schleife ist es aber so, dass hier dann alle "3er-Pakete" so oft ausgeführt werden, wie die Schleife es angibt.
Also zusammengefasst: Ich möchte die Schleife erst dann fortsetzen, wenn alle Threads beendet sind, aber keine weitere Schleife á la:
hinzufügen, da sich so die GUI aufhängt.
Code:
Task progress = new Task<Void>() {
@Override
public Void call() {
this.updateProgress(dwtable.getItems().size(), 1);
while (ydown.Percent < 100) {
if (isCancelled()) {
break;
}
setPercent(null, ydown.Percent);
updateProgress(ydown.Percent, 100);
System.out.println("Prozent: " + ydown.Percent);
}
updateProgress(100, 100);
ydown.Percent = 0;
return null;
}
};
Task download = new Task<Void>() {
@Override
public Void call() {
ydown.download(dwtable.getItems().get(zaehler).getYouTube());
zaehler++;
finish = true;
return null;
}
};
for(Track tr : dwtable.getItems())
{
try {
executor.execute((Runnable) tr);
testProg.progressProperty().bind(progress.progressProperty());
executor.execute(download);
executor.execute(progress);
finish = false;
} catch (Exception ex) {
Logger.getLogger(MainFrameController.class.getName()).log(Level.SEVERE, null, ex);
}
}
und in Track:
Code:
@Override
protected Void call() throws Exception
{
mfc = new MainFrameController();
this.updateProgress(ProgressIndicator.INDETERMINATE_PROGRESS, 100);
while(percent < 100)
{
updateProgress(percent, 100);
}
updateProgress(100, 100);
percent = 0;
return null;
}
|
|
|
02/01/2015, 21:56
|
#2
|
elite*gold: 34
Join Date: Apr 2011
Posts: 1,475
Received Thanks: 1,227
|
Verwende ThreadPoolExecutor und sogenannte "Watchdogs".
Glücklicherweise habe ich auf meinen Github Acc ein Programm welches sehr stark mit Threads arbeitet, und da werden ThreadPoolExecutoren und Watchdogs verwendet.
Wirf ein Blick rein, vielleicht wird es dir helfen: Und das Projekt generell:
Und was ich von deinem Code herleiten konnte, willst du eine Progressbar(und andere Progress änderungen) darstellen oder? Ich würde dann das Observer verwenden(Observer Nutzung auch auf meinem Git Acc: )
|
|
|
02/01/2015, 22:08
|
#3
|
elite*gold: 0
Join Date: Mar 2013
Posts: 3,184
Received Thanks: 1,317
|
Quote:
Originally Posted by XxharCs
Und was ich von deinem Code herleiten konnte, willst du eine Progressbar(und andere Progress änderungen) darstellen oder? Ich würde dann das Observer verwenden(Observer Nutzung auch auf meinem Git Acc: )
|
Prinzipiell ja, hier geht es aber nicht um eine einzige Progressbar sondern um mehrere ProgressBars, die in einer TableView sind.
|
|
|
02/01/2015, 23:02
|
#4
|
elite*gold: 34
Join Date: Apr 2011
Posts: 1,475
Received Thanks: 1,227
|
Ich werde mich morgen hier nochmal melden/diesen Beitrag editieren mit einer Lösung, weil ich schon eine Idee habe (Natürlich falls sich keiner schon vor mir gemeldet hat )
Edit: Ohne das du jetzt groß dein Design änderst, und sehe ja das dein Code den ExecuterService(nice! ) verwendet, müsstest du trotzdem eine while-Schleife reinhauen :/
Code:
executor.shutdown(); // den ExecuterService schließen nachdem du Threads mit ihm gestartet hast
while (!executor.isTerminated()) {} // wartet bis alle Thread fertig sind
Bei dem Observer Prinzip müsstest du in diesem Fall etwas mehr Code ändern :/ Lass mich wissen falls du es doch anders haben möchtest, und ich schreibe ne kurze Application die mit mehreren Progressbars arbeitet und das Obserer Prinzip verwendet
Edit2: Obwohl wenn du das Observer Pattern anwendest, müsstest du auch irgendwann mal nachfragen ob progress jetzt 100% ist oder so, zwar ist man da Flexibler wie zb if(progress == 100) dann enable wieder diese bestimmten Funktionen oder so.
Was genau sollte denn passieren nachdem die Threads fertig sind? Sind dann bestimmte Funktionen wieder zur Verfügung gestellt oder wie?
|
|
|
02/02/2015, 14:11
|
#5
|
elite*gold: 0
Join Date: Mar 2013
Posts: 3,184
Received Thanks: 1,317
|
Ich werde nachher den kompletten relevanten Code einstellen. Der Code ist allerdings !noch! ziemlich unübersichtlich und noch nicht wirklich Objektorientiert.
Also das Prinzip ist folgendermaßen - hoffe es ist halbwegs verständlich dargestellt:
-> Downloadknopf gedrückt
-> Für jeden Track (Musikstück) in TableView
--> Lade Track herunter
--> Update Gesamtprogressbar (Alle Tracks) anhand (noch nicht implementiert, testweise lediglich Fortschritt von einzelnem Track)
--> Update jeweilige Progressbar des Tracks im TableView
--> Wenn Track heruntergeladen, starte Download des nächsten Tracks
--> GUI soll weiterhin aktiv bleiben ohne zu blockieren
*Edit: Das sollte alles relevantes sein. Ich muss mich leider beeilen, daher kann es sein, dass etwas fehlt.
MainFrameController:
Code:
public class MainFrameController implements Initializable {
@FXML
private TableColumn<Track, String> colDwTitle;
@FXML
private TableColumn<Track, Double> colDwProgress;
@FXML
private TableView<Track> dwtable;
ObservableList<Track> tracks = FXCollections.observableArrayList();
SQLite sql;
public static YouTube ydown;
@Override
public void initialize(URL url, ResourceBundle rb) {
sql = new SQLite();
tracks = sql.getAllSongs();
dwtable.setItems(tracks);
colDwTitle.setCellValueFactory((p) -> new SimpleStringProperty(p.getValue().getArtist() + " - " + p.getValue().getName()));
colDwProgress.setCellValueFactory(new PropertyValueFactory<>(
"progress"));
colDwProgress.setCellFactory(ProgressBarTableCell.<Track>forTableColumn());
}
@FXML
private void btnDownload(ActionEvent event)
{
//ExecutorService executor = Executors.newFixedThreadPool(1, new ThreadFactory() {
ThreadPoolExecutor executor;
executor = new ThreadPoolExecutor(3, 3, 2, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(3));
//ExecutorService es = Executors.newCachedThreadPool();
ydown = new YouTube();
int zaehler = 0;
Task progress = new Task<Void>() {
@Override
public Void call() {
this.updateProgress(dwtable.getItems().size(), 1);
while (ydown.Percent < 100) {
if (isCancelled()) {
break;
}
setPercent(null, ydown.Percent);
updateProgress(ydown.Percent, 100);
System.out.println("Prozent: " + ydown.Percent);
}
updateProgress(100, 100);
ydown.Percent = 0;
return null;
}
};
Task download = new Task<Void>() {
@Override
public Void call() {
ydown.download(dwtable.getItems().get(zaehler).getYouTube());
zaehler++;
finish = true;
return null;
}
};
for(Track tr : dwtable.getItems())
{
try {
executor.execute((Runnable) tr);
testProg.progressProperty().bind(progress.progressProperty());
executor.execute(download);
executor.execute(progress);
finish = false;
} catch (Exception ex) {
Logger.getLogger(MainFrameController.class.getName()).log(Level.SEVERE, null, ex);
}
}
executor.shutdown();
while(!executor.isTerminated())
{
}
System.out.println("Finished All Threads");
}
public void setPercent(Track tr, double per)
{
Track.percent = per;
}
}
Track:
Code:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package chartsjavafx.services;
import chartsjavafx.MainFrameController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.concurrent.Task;
import javafx.scene.control.ProgressIndicator;
/**
*
* @author Tobias
*/
public class Track extends Task<Void> {
String name, art, rem, lab, gen, dat, ytb;
//IntegerProperty downloadProgress;
private DoubleProperty downloadProgress;
public static double percent;
public static final int NUM_ITERATIONS = 100;
MainFrameController mfc;
public Track(String trackname, String artist, String remix, String label, String genretr, String date, String youtube) {
name = trackname;
art = artist;
rem = remix;
lab = label;
gen = genretr;
dat = date;
ytb = youtube;
downloadProgress = new SimpleDoubleProperty(0);
}
public ArrayList<String> getTrackInfo() {
ArrayList<String> info = new ArrayList<String>();
info.add(name);
info.add(art);
info.add(rem);
info.add(lab);
info.add(gen);
info.add(dat);
info.add(ytb);
return info;
}
public String getTrack() {
String track = name + " - " + art + " - " + rem + " - " + lab + " - " + gen + " - " + dat;
return track;
}
public String getName() {
return name;
}
public String getArtist() {
return art;
}
public String getRemixer() {
return rem;
}
public String getLabel() {
return lab;
}
public String getGenre() {
return gen;
}
public String getReleaseDate() {
return dat;
}
public String getYouTube() {
return ytb;
}
public DoubleProperty getDownloadProgress() {
return downloadProgress;
}
public void setProgressBar(double percent)
{
this.downloadProgress = new SimpleDoubleProperty(percent);
}
@Override
protected Void call() throws Exception
{
mfc = new MainFrameController();
this.updateProgress(ProgressIndicator.INDETERMINATE_PROGRESS, 100);
while(percent < 100)
{
updateProgress(percent, 100);
}
updateProgress(100, 100);
percent = 0;
return null;
}
}
Youtube:
Code:
import chartsjavafx.MainFrameController;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLEncoder;
import javax.net.ssl.HttpsURLConnection;
import com.google.gson.*;
import com.google.gson.stream.JsonReader;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.*;
public class YouTube {
public static int filesize;
public static float totalDataRead = 0;
public static float Percent = 0;
public static void download(String ytburl)
{
Percent = 0;
//ytburl = "https://www.youtube.com/watch?v=h5-mjniYSIY";
try {
/*
JSON holen
*/
String urlparameters = "api=advanced&format=JSON&video=" + ytburl;
String url = "http://youtubeinmp3.com/fetch/?" + urlparameters;
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", USER_AGENT);
responseCode = con.getResponseCode();
System.out.println("\nSending 'GET' request to URL : " + url);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
String json = String.valueOf(response);
String dwnlink = "";
String filename = "";
/*
JSON auslesen, DownloadLink holen
*/
JSONObject obj2 = new JSONObject(json);
filename = obj2.getString("title") + ".mp3";
dwnlink = obj2.getString("link");
URL url2 = new URL(dwnlink);
HttpURLConnection connection = (HttpURLConnection) url2.openConnection();
int filesize = connection.getContentLength();
float totalDataRead = 0;
java.io.BufferedInputStream in2 = new java.io.BufferedInputStream(connection.getInputStream());
java.io.FileOutputStream fos = new java.io.FileOutputStream(filename);
java.io.BufferedOutputStream bout = new BufferedOutputStream(fos, 1024);
byte[] data = new byte[1024];
int i = 0;
while ((i = in2.read(data, 0, 1024)) >= 0)
{
totalDataRead = totalDataRead + i;
bout.write(data, 0, i);
Percent = (totalDataRead * 100) / filesize;
}
bout.close();
in.close();
org.apache.commons.io.FileUtils.copyURLToFile(new URL(dwnlink), new File(DATAPATH + filename));
System.out.println("Download done!");
//print result
} catch (MalformedURLException ex) {
Logger.getLogger(YouTube.class.getName()).log(Level.SEVERE, null, ex);
} catch (ProtocolException ex) {
Logger.getLogger(YouTube.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(YouTube.class.getName()).log(Level.SEVERE, null, ex);
} catch (JSONException ex) {
Logger.getLogger(YouTube.class.getName()).log(Level.SEVERE, null, ex);
} /*catch (JSONException ex) {
Logger.getLogger(YouTube.class.getName()).log(Level.SEVERE, null, ex);
}*/
}
|
|
|
02/02/2015, 15:25
|
#6
|
elite*gold: 34
Join Date: Apr 2011
Posts: 1,475
Received Thanks: 1,227
|
Asooo, ja das kann man auf 2 Arten machen, die eine Art mit join() und die andere ivokeAll() oder submit().
Bei der 1 Art:
Die Threads in ein Array packen, sie starten und dann mit einer Schleife für die Threads ein join(), also:
Code:
for(i = 0; i < threads.length; i++)
threads[i].join();
Der Join wartet bis der Thread vor ihm fertig ist und startet den. Die Reihenfolge ist nicht garantiert^^
Die 2 Art:
Mit Future Objekt arbeiten und der Methode invokeAll() vom ThreadPoolExecutor. Dieses Future Objekt beinhaltet dann den Status des/(r) Threads.
Code:
List<Future<Runnable>> futures = new ArrayList<Future<Runnable>>();
// in deiner for-each jetzt
Future fTrack = executor.submit(tr); // oder submit((Runnable)tr); habs ned getestet
futures.add(fTrack);
for(Futures<Runnable> f : futures) {
f.get(); // was passiert in dieser for-Schleife? Es wird ein Track nach dem anderen abgearbeitet (also wenn eins fertig ist dann das nächste)
}
Ich würde zusätzlich sagen, dass in deiner Tracks Klasse, deine download und progress Tasks ausgeführt werden sollten.
Edit: Mit der 2 Art selbst habe ich mich bis jetzt noch nicht wirklich beschäftigt(also was das starten des nächsten Threads wenn der jetzige Thread beendet wurde, angeht), deshalb meine recherche dazu:
Ich hoffe das hilft dir weiter!
|
|
|
02/02/2015, 17:19
|
#7
|
elite*gold: 0
Join Date: Mar 2013
Posts: 3,184
Received Thanks: 1,317
|
Danke, werde ich nachher ausprobieren wenn ich zuhause bin.
Bzgl. Der ersten methode:
Wenn ich die threads in ein arrax packe und diese mit einer schleife ausführe werden doch dann alle threads nacheinander ausgeführt also erst der download und danach die progressbar und nicht beide gleichzeitig oder ? Das heißt ich müsste entweder drei schleifen anlegen oder die threads in den einzelnen threads verschachteln also in download thread den progress thread aufrufen oder sehe ich das falsch ?
Edit: rein theoretisch sollte sich die GUI bei der methode auch aufhängen, das heißt die schleife(n) müssten auch wiederum in einem weiteren thread ausgelagert werden. Da sieht die zweite methode wesentlich eleganter aus, wobei auch hier so wie ich das sehe, ein weiterer thread erforderlich ist. Aber wie gesagt : ich probiere es nachher aus und melde mich nochmal.
|
|
|
02/02/2015, 20:17
|
#8
|
elite*gold: 34
Join Date: Apr 2011
Posts: 1,475
Received Thanks: 1,227
|
Ja also, wie mein letzter Satz lautete vor dem Edit:
Quote:
Ich würde zusätzlich sagen, dass in deiner Tracks Klasse, deine download und progress Tasks ausgeführt werden sollten.
|
Weil eigentlich müssten die Prozente nicht mehr stimmen wenn du das in 3 verschiedenen Threads machst. Du kannst nicht garantieren ob jetzt dein "download" oder "progress"-Task zuerst fertig sein wird, mache das am besten in der Track Klasse oder in der Youtube Klasse und von dort aus benachrichtigst du deine GUI das sich was geändert hat und somit die Progressbar ändert. (Da würde eigentlich das Observer Pattern/Prinzip ins Spiel kommen)
|
|
|
02/02/2015, 21:31
|
#9
|
elite*gold: 0
Join Date: Mar 2013
Posts: 3,184
Received Thanks: 1,317
|
Vielen Dank für deine Hilfe ich habe es jetzt vorübergehend mit der 1. Methode gelöst, der Download funktioniert noch nicht optimal, das ist aber ein anderes Problem.
Für diejenigen, die an der Lösung interessiert sind, hier meine Lösung als Beispiel:
Tracks.java
Code:
@Override
protected Void call() throws Exception
{
updateProgress(100, 100); //Progressbar füllen
percent = 0;
Thread.sleep(1000); //1 Sekunde warten
return null;
}
Controller.java
Code:
Runnable[] threads = new Runnable[dwtable.getItems().size()]; //Lege ein Array für die Runnables aus Tracks an
Task startprocess = new Task<Void>() {
@Override
public Void call() {
for(int i = 0; i < threads.length; i++)
{
Thread thread1 = new Thread((Runnable) threads[i], "Track"); //Es wird nun für das Runnable ein Thread angelegt
try {
thread1.start(); //Thread starten
thread1.join(); //Warten, bis dieser beendet wurde
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
return null;
}
};
int z = 0;
for(Track tr : dwtable.getItems())
{
try {
System.out.println("Füge Thread " + z + " zu Array hinzu");
threads[z] = (Runnable) tr;
z++;
} catch (Exception ex) {
ex.printStackTrace();
}
}
|
|
|
02/02/2015, 21:57
|
#10
|
elite*gold: 724
Join Date: Mar 2011
Posts: 10,480
Received Thanks: 3,319
|
Danke für das Posten deiner Lösung.
#closed (on request)
|
|
|
|
Similar Threads
|
[HELP] Erkennen wenn Programm Beendet wird. (Task Manager etc)
03/15/2014 - AutoIt - 13 Replies
Wie mach ich das das mein tool mir eine MsgBox absendet wenn der Prozess Test.exe über den Task Manager geschlossen wird?
Hab das Problem mit MySQL. Register, Login und alles klappt nur wenn ich es über den Tast manager schließe führt er die Funktion _Logout() nicht aus wie kann man das ändern.
Danke im vorraus!
|
Wenn ich Putty schließe beendet sich mein TS3 Server
12/26/2011 - Main - 6 Replies
Moin Leute,
wie oben beschrieben habe ich ein problem mit meinem ts3 server der über nen root läuft.
und wenn ich den ts3 server am laufen habe und mein putty programm beende, beendet sich auch der ts3 server.
Ich bedanke mich im vorraus für die hilfe und hoffe ich bin in dem Bereich richtig.
lg
|
While schleife pausieren und wieder fortsetzen!
06/16/2010 - AutoIt - 6 Replies
Hallo,
ich möchte mein Script pausieren können mit "p" bzw. beenden mit "x"
leider bin ich trotz diverser Suchaktionen noch nicht schlauer geworden vlt. kann mir jemand helfen
MfG
|
Flyff beendet sich wenn Gameguard zuende geladen ist
11/30/2007 - Flyff - 21 Replies
BITTE HELFEN DAS SPIEL FLYFF macht update dann starte ich dann kommt game gaurd ladet danach geht es zu
|
Hmm Aapplikation wird beendet wenn ich das
10/04/2005 - Main - 1 Replies
...Terminal aus mache. Also ich folgendes problem auf linux, sobald ich z.b einen server eröffnet habe in einem terminal und dann das terminal zu machen beendet er auch automatisch den server... Mit crontabs probier ich gerade rum ab anscheinend muss dafür auch das terminal auf bleiben.
|
All times are GMT +2. The time now is 02:25.
|
|