Hallo,
ich schreibe derzeit eine kleine Applikation, die nach gewissen Einstellungen Mails aus einem Repository entnimmt und diese versendet. Um den Mailserver nicht zu hämmern, passiert dies über eine limitierte Anzahl Threads.
Ich erzeuge eine Arrayliste mit dem Primärschlüsseln der Datensätze, welche versendet werden sollen. Diese gebe ich nacheinander jeweils einem Thread mit. Dieser liest dann den entsprechenden Datensatz, bringt die Mail auf den Weg und soll sich dann beenden.
Die Hauptklasse:
Die Threadklasse:
Mein Problem dabei ist, dass die Threads nicht beendet werden. Debugge ich diese Chose, so sehe ich, dass die maximale Anzahl an Threads unter dem Mainthread stehen und sich nicht bewegen. Normalerweise würde ich erwarten, dass die run()-Methode sich beendet, dann danach der Konstruktor verlassen wird und damit der darunterliegende Thread beendet werden würde.
Leider passiert dies nicht. Ich würde ungerne zu so unsauberen Lösungen wie Thread.stop() greifen müssen.
Kann jemand einen Denkanstoß geben?
Danke.
ich schreibe derzeit eine kleine Applikation, die nach gewissen Einstellungen Mails aus einem Repository entnimmt und diese versendet. Um den Mailserver nicht zu hämmern, passiert dies über eine limitierte Anzahl Threads.
Ich erzeuge eine Arrayliste mit dem Primärschlüsseln der Datensätze, welche versendet werden sollen. Diese gebe ich nacheinander jeweils einem Thread mit. Dieser liest dann den entsprechenden Datensatz, bringt die Mail auf den Weg und soll sich dann beenden.
Die Hauptklasse:
Java:
public class Mailmonitor2 {
public static String CONFIG_FILE = "src/mailmonitor2.conf";
public static String STD_QUERY = "select ProgSessionID from MailV3 where Status = 2 order by Prioritaet desc";
private Properties properties=null;
public static void main(String[] args) {
new Mailmonitor2();
}
public Mailmonitor2() {
this.InitProperties();
[Stuff happens]
while(true) {
//Main Loop!
while(ProgSessionIDs.size()>0) {
if(Thread.activeCount()<max_threads)
new Mailthread(ProgSessionIDs.remove(0), this.GetConnection());
Thread.yield();
}
if(ProgSessionIDs.size()==0) {
try {
Thread.sleep(Integer.parseInt(this.properties.getProperty("Main_Sleep_Time")));
//Neues Laden
try {
if(statement.execute())
resultset = statement.getResultSet();
} catch (SQLException sqle) {
System.err.println(String.format("Fehler bei erneuten Ausführung des Statements (%s).", Mailmonitor2.STD_QUERY));
try {
conn.close();
} catch (SQLException e) {}
return;
}
ProgSessionID=null;
try {
while(resultset.next()) {
ProgSessionID = resultset.getString("ProgSessionID");
ProgSessionIDs.add(ProgSessionID);
}
} catch (SQLException sqle) {
System.err.println(String.format("Konnte Feld 'ProgSessionID' während der Auswertung des Hauptqueries (%s) nicht extrahieren (%s).", Mailmonitor2.STD_QUERY, sqle.toString()));
try {
conn.close();
} catch (SQLException e) {}
System.exit(-2);
}
} catch (InterruptedException ie) {
System.err.println(String.format("InterruptedException während Sleep des Hauptthreads: %s", ie.toString()));
try {
conn.close();
} catch (SQLException e) {}
System.exit(-4);
}
}
}
}
public void InitProperties() {
[Einlesen Konfigurationsdatei]
}
public Connection GetConnection() {
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
} catch (ClassNotFoundException cnfe) {
return null;
} catch (IllegalAccessException iae) {
return null;
} catch (InstantiationException ie) {
return null;
}
String Connection = String.format("jdbc:mysql://%s/%s?user=%s&password=%s&autoReconnectForPools=true",this.properties.getProperty("MySQL.Host"),this.properties.getProperty("MySQL.Database"),this.properties.getProperty("MySQL.User"),this.properties.getProperty("MySQL.Password"));
Connection conn = null;
try {
conn = DriverManager.getConnection(Connection);
} catch (SQLException sqle) {
return null;
}
return conn;
}
}
Die Threadklasse:
Java:
public class Mailthread implements Runnable {
private static String STD_QUERY = "SELECT * FROM MailV3 WHERE ProgSessionID = '%s'";
private static String DONE_STMT = "UPDATE MailV3 SET Status = 4 WHERE ProgSessionID = '%s'";
private String ProgSessionID;
private Connection conn;
private PreparedStatement statement;
public Mailthread(String ProgSessionID, Connection conn) {
this.ProgSessionID = ProgSessionID;
this.conn = conn;
try {
this.statement = this.conn.prepareStatement(String.format(STD_QUERY, ProgSessionID));
} catch (SQLException sqle) {
System.err.println(String.format("Konnte Statement für Thread %s nicht vorbereiten.", Mailthread.STD_QUERY));
return;
}
new Thread(this).start();
}
@Override
public void run() {
// Abfrage auf DB machen
if (this.statement == null) {
return;
}
ResultSet resultset = null;
try {
if(this.statement.execute())
resultset = this.statement.getResultSet();
} catch (SQLException e) {
return;
}
if (resultset == null) {
return;
}
try {
resultset.first();
} catch (SQLException sqle) {
System.err.println(String.format("Keinen Datensatz für %s gefunden.", this.ProgSessionID));
return;
}
[Mailvorbereitung]
try {
Transport transport = session.getTransport("smtp");
transport.connect();
Transport.send(msg);
} catch (SendFailedException sfe) {
System.err.println(String.format("Das Versenden von Mail %s schlug fehl (%s).", this.ProgSessionID, sfe.toString()));
} catch (MessagingException me) {
System.err.println(String.format("Das Versenden von Mail %s schlug fehl (%s).", this.ProgSessionID, me.toString()));
return;
}
try {
this.statement = this.conn.prepareStatement(String.format(Mailthread.DONE_STMT, this.ProgSessionID));
} catch (SQLException sqle) {
System.err.println(String.format("Konnte Statement für Update des Statusfeldes für Mail %s nicht vorbereiten (%s): %s", this.ProgSessionID, String.format(Mailthread.DONE_STMT, this.ProgSessionID), sqle.toString()));
return;
}
try {
this.statement.execute();
} catch (SQLException sqle) {
System.err.println(String.format("Statement für Update des Status nach erfolgreichem Versand der Mail %s konnte nicht ausgeführt werden (%s): %s", this.ProgSessionID, String.format(Mailthread.DONE_STMT, this.ProgSessionID), sqle.toString()));
return;
}
try {
this.conn.close();
} catch (SQLException e) {}
}
}
Mein Problem dabei ist, dass die Threads nicht beendet werden. Debugge ich diese Chose, so sehe ich, dass die maximale Anzahl an Threads unter dem Mainthread stehen und sich nicht bewegen. Normalerweise würde ich erwarten, dass die run()-Methode sich beendet, dann danach der Konstruktor verlassen wird und damit der darunterliegende Thread beendet werden würde.
Leider passiert dies nicht. Ich würde ungerne zu so unsauberen Lösungen wie Thread.stop() greifen müssen.
Kann jemand einen Denkanstoß geben?
Danke.