Hallo,
ich habe ein Problem, bzw. ein Verhalten, was ich mir nicht ganz erklären kann und worfür ich eine Lösung suche. Ich habe ein GUI aus dem ich einen Test starte, der dann eine gewisse Zeit läuft und dann beendet wird oder vorher über einen Stop Button beendet wird. Das Ganze habe ich mit SwingWorker Threads realisiert. Hier als Referenz der komplette Code:
Das Problem:
Wenn ich den Stop Button drücke bzw. die Zeit abgelaufen ist wird der Thread über die cancel() Methode
beendet:
Beim cancel() wird der Thread beendet, aber es wird anscheinend der Code der nach der while-Schleife steht nicht mehr ausgeführt:
Ich sehe auf der Console den Text "Test Stopped" aber nicht den Text "System.out.println("DB Test " + randomUUIDString + " Finished!");" aus den einzelnen ProcessWorkerDbTest Threads!?
Für mich wäre es wichtig nach beenden der DB Tests Code auszuführen um "aufzuräumen", sprich z.B. die DB Sessions zu terminieren, etc.
Hat jemand eine Erklärung/Idee was ich hier falsch mache und warum dieser Code nicht mehr ausgeführt wird?
Gruß
Ralf
ich habe ein Problem, bzw. ein Verhalten, was ich mir nicht ganz erklären kann und worfür ich eine Lösung suche. Ich habe ein GUI aus dem ich einen Test starte, der dann eine gewisse Zeit läuft und dann beendet wird oder vorher über einen Stop Button beendet wird. Das Ganze habe ich mit SwingWorker Threads realisiert. Hier als Referenz der komplette Code:
Java:
package oracle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextArea;
import javax.swing.JToggleButton;
import javax.swing.WindowConstants;
import javax.swing.border.BevelBorder;
import javax.swing.border.SoftBevelBorder;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit www.cloudgarden.com for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
@SuppressWarnings("serial")
public class TestMultipleUser extends javax.swing.JFrame {
private JTextArea jTAOutput;
private JButton jBExit;
private JToggleButton jTBStartStop;
private JSlider jSNoUser;
private JLabel jLabel1;
private JLabel jLTestRemaining;
private JScrollPane jScrollPane1;
private ProcessWorkerCounter pc;
private Vector<ProcessWorkerDbTest> vcDbTest;
/**
* Auto-generated main method to display this JFrame
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TestMultipleUser inst = new TestMultipleUser();
inst.setLocationRelativeTo(null);
inst.setVisible(true);
}
});
}
public class ProcessWorkerCounter extends SwingWorker<Void, String>
{
private JLabel jLCounter;
private long seconds;
private Timer timerCounter;
private Vector<ProcessWorkerDbTest> vcDbTest;
private ExecutorService esDbTest;
//Konstruktor
public ProcessWorkerCounter(JLabel counter, long seconds, Vector<ProcessWorkerDbTest> vcDbTest)
{
this.jLCounter = counter;
this.seconds = seconds;
this.vcDbTest = vcDbTest;
}
//getter - Return Timer Object
public Timer getTimerCounter() {
return timerCounter;
}
class TaskCounter extends TimerTask
{
@Override public void run()
{
seconds--;
long hh = seconds / 3600;
long mm = (seconds % 3600) / 60;
long ss = seconds - (hh * 3600) - (mm * 60);
DecimalFormat format = new DecimalFormat("00");
publish(format.format(hh) + ":" + format.format(mm) + ":" + format.format(ss));
if (seconds == 0) {
for (int i=0; i < vcDbTest.size(); i++) {
((ProcessWorkerDbTest)vcDbTest.elementAt(i)).cancel(true);
}
pc.getTimerCounter().cancel();
publish("Test finished!");
}
}
}
@Override
protected Void doInBackground() throws Exception
{
//hier l�uft alles in einem eigenen Thread (nebenl�ufig) ab. Es ist also egal wie lange die Abarbeitung hier dauert.
this.timerCounter = new Timer();
timerCounter.scheduleAtFixedRate(new TaskCounter(), 0, 1000);
//System.out.println("Start Tests: " + vcDbTest.size());
this.esDbTest = new ThreadPoolExecutor(33, 33, 1L,TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>());
for (int i=0; i < vcDbTest.size(); i++) {
esDbTest.execute((Runnable)vcDbTest.elementAt(i));
}
return null;
}
@Override
protected void process(List<String> chunks)
{
//hier l�uft alles auf dem EDT (Event Dispatch Thread). Darum k�nnen (und sollten) wir hier die GUI Komponenten manipulieren.
for(int i = 0; i < chunks.size(); i++)
{
jLCounter.setText(chunks.get(i));
//jTAOutput.append(System.getProperty("line.separator"));
}
}
}
public class ProcessWorkerDbTest extends SwingWorker<Void, String>
{
private JTextArea jTAOutput;
public ProcessWorkerDbTest(JTextArea textArea)
{
this.jTAOutput = textArea;
}
@Override
protected Void doInBackground() throws Exception
{
//hier l�uft alles in einem eigenen Thread (nebenl�ufig) ab. Es ist also egal wie lange die Abarbeitung hier dauert.
UUID uuid = UUID.randomUUID();
final String randomUUIDString = uuid.toString();
while (!isCancelled()) {
for (int i=1000; i>=0; i--) {
//System.out.println("DB Test " + randomUUIDString + " Run: " + i);
publish("DB Test " + randomUUIDString + " Run: " + i);
TimeUnit.SECONDS.sleep(1);
}
}
System.out.println("DB Test " + randomUUIDString + " Finished!");
return null;
}
@Override
protected void process(List<String> chunks)
{
//hier l�uft alles auf dem EDT (Event Dispatch Thread). Darum k�nnen (und sollten) wir hier die GUI Komponenten manipulieren.
for(int i = 0; i < chunks.size(); i++)
{
jTAOutput.append(chunks.get(i));
jTAOutput.append(System.getProperty("line.separator"));
}
}
}
public class TestTableSize {
private String name;
private int size;
public TestTableSize(String name, int size) {
this.name = name;
this.size = size;
}
public String getTestTableSize() {
return this.name + ":" + this.size + " MB";
}
public String getName() {
return this.name;
}
public int getSize() {
return this.size;
}
}
public TestMultipleUser() {
super();
initGUI();
}
private void initGUI() {
try {
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
getContentPane().setLayout(null);
this.setTitle("Test Multiple User");
{
jScrollPane1 = new JScrollPane();
getContentPane().add(jScrollPane1);
jScrollPane1.setBounds(24, 142, 816, 216);
{
jTAOutput = new JTextArea();
jScrollPane1.setViewportView(jTAOutput);
jTAOutput.setBounds(24, 142, 816, 216);
jTAOutput.setEditable(false);
}
}
{
jBExit = new JButton();
getContentPane().add(jBExit);
jBExit.setText("Exit");
jBExit.setBounds(852, 335, 80, 23);
jBExit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
jBExitActionPerformed(evt);
}
});
}
{
jLTestRemaining = new JLabel();
getContentPane().add(jLTestRemaining);
jLTestRemaining.setBounds(136, 110, 130, 20);
jLTestRemaining.setBorder(new SoftBevelBorder(BevelBorder.LOWERED, null, null, null, null));
}
{
jLabel1 = new JLabel();
getContentPane().add(jLabel1);
jLabel1.setText("Remining Time");
jLabel1.setBounds(36, 114, 111, 16);
}
{
jSNoUser = new JSlider();
getContentPane().add(jSNoUser);
getContentPane().add(getJTBStartStop());
jSNoUser.setBounds(352, 81, 237, 45);
jSNoUser.setMinimum(1);
jSNoUser.setMaximum(33);
jSNoUser.setMajorTickSpacing(4);
jSNoUser.setMinorTickSpacing(1);
jSNoUser.createStandardLabels(1);
jSNoUser.setPaintLabels(true);
jSNoUser.setPaintTicks(true);
jSNoUser.setValue(4);
jSNoUser.setFont(new java.awt.Font("Segoe UI",0,11));
}
pack();
this.setSize(959, 431);
} catch (Exception e) {
//add your error handling code here
e.printStackTrace();
}
}
private void jBExitActionPerformed(ActionEvent evt) {
System.exit(0);
}
private void jTBStartStopActionPerformed(ActionEvent evt) {
toggleButtonAction();
}
private void toggleButtonAction() {
if (jTBStartStop.isSelected()) {
long seconds = 30;
this.vcDbTest = new Vector<ProcessWorkerDbTest>();
for (int i = 1; i <= jSNoUser.getValue(); i++) {
vcDbTest.add(new ProcessWorkerDbTest(jTAOutput));
}
this.pc = new ProcessWorkerCounter(jLTestRemaining, seconds, vcDbTest);
pc.execute();
} else {
System.out.println("Stop Tests: " + vcDbTest.size());
for (int i=0; i < vcDbTest.size(); i++) {
((ProcessWorkerDbTest)vcDbTest.elementAt(i)).cancel(true);
}
pc.getTimerCounter().cancel();
System.out.println("Test stopped!!");
}
}
private JToggleButton getJTBStartStop() {
if(jTBStartStop == null) {
Icon icon = new ImageIcon("StartTriangel20.png");
jTBStartStop = new JToggleButton("", icon);
getContentPane().add(jTBStartStop);
jTBStartStop.setBounds(641, 72, 20, 20);
jTBStartStop.setBorderPainted(false);
jTBStartStop.setIcon(new ImageIcon(getClass().getClassLoader().getResource("StartTriangel20.png")));
jTBStartStop.setSelectedIcon(new ImageIcon(getClass().getClassLoader().getResource("StopQuad20.png")));
jTBStartStop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
jTBStartStopActionPerformed(evt);
}
});
jTBStartStop.setVisible(true);
}
return jTBStartStop;
}
}
Das Problem:
Wenn ich den Stop Button drücke bzw. die Zeit abgelaufen ist wird der Thread über die cancel() Methode
Java:
for (int i=0; i < vcDbTest.size(); i++) {
((ProcessWorkerDbTest)vcDbTest.elementAt(i)).cancel(true);
}
Java:
private void toggleButtonAction() {
if (jTBStartStop.isSelected()) {
long seconds = 30;
this.vcDbTest = new Vector<ProcessWorkerDbTest>();
for (int i = 1; i <= jSNoUser.getValue(); i++) {
vcDbTest.add(new ProcessWorkerDbTest(jTAOutput));
}
this.pc = new ProcessWorkerCounter(jLTestRemaining, seconds, vcDbTest);
pc.execute();
} else {
System.out.println("Stop Tests: " + vcDbTest.size());
for (int i=0; i < vcDbTest.size(); i++) {
((ProcessWorkerDbTest)vcDbTest.elementAt(i)).cancel(true);
}
pc.getTimerCounter().cancel();
System.out.println("Test stopped!!");
}
}
Beim cancel() wird der Thread beendet, aber es wird anscheinend der Code der nach der while-Schleife steht nicht mehr ausgeführt:
Java:
while (!isCancelled()) {
for (int i=1000; i>=0; i--) {
//System.out.println("DB Test " + randomUUIDString + " Run: " + i);
publish("DB Test " + randomUUIDString + " Run: " + i);
TimeUnit.SECONDS.sleep(1);
}
}
System.out.println("DB Test " + randomUUIDString + " Finished!");
return null;
Ich sehe auf der Console den Text "Test Stopped" aber nicht den Text "System.out.println("DB Test " + randomUUIDString + " Finished!");" aus den einzelnen ProcessWorkerDbTest Threads!?
Für mich wäre es wichtig nach beenden der DB Tests Code auszuführen um "aufzuräumen", sprich z.B. die DB Sessions zu terminieren, etc.
Hat jemand eine Erklärung/Idee was ich hier falsch mache und warum dieser Code nicht mehr ausgeführt wird?
Gruß
Ralf