addShutdownHook tut nicht den gewünschten Dienst

genodeftest

Erfahrenes Mitglied
Hallo
Ich habe folgendes Problem:
Ich habe ein Programm geschrieben, dass die Benutzung des Computers Protokollieren soll. Dazu führe ich diesen Code aus:

Code:
package de.genodeftest.computerzeit;

import ...


public class Counter
{
	private static SimpleDateFormat date_complete = new SimpleDateFormat("yyyy MM dd HH:mm:ss.SSS");
	
	
	private Counter(long currentTimeMillis)
	{
		// the ShutdownHook should be run when JVM gets signal to exit
		Runtime.getRuntime().addShutdownHook(
				new ThreadToRunAtShutdown(currentTimeMillis)
		);
	}

	public static void main(String[] args)
	{
		try
		{
			String str = args[0];
			
			Scanner sc = new Scanner(str);
			if(sc.hasNext("save"))
			{
				saveXMLtoODS(new File("data.xml"));
				System.out.println("saved to ODS");
			}
			else
			{
				Counter c = new Counter(System.currentTimeMillis());
				c.run();
			}
			
		}
		catch(Exception e)
		{
			Counter c = new Counter(System.currentTimeMillis());
			c.run();
		}
		
	}

	private void run()
	{
		synchronized(this)
		{
			try
			{
				this.wait();
				//this.wait(1200);
				//System.exit(1);
			}
			catch (Exception e)
			{
				saveErrorLog(e, System.currentTimeMillis());
			}
		}
	}

dabei übergebe ich eine Instanz des Threads ThreadToRunAtShutdown, der so aussieht (Hilfsmethoden entfernt)

Code:
class ThreadToRunAtShutdown extends Thread
{
	private File file = new File("data.xml");
	private File fTemp;

	private XMLOutputFactory outFact = XMLOutputFactory.newInstance();
	private XMLStreamWriter writer;

	private static SimpleDateFormat date_complete = new SimpleDateFormat("yyyy MM dd HH:mm:ss.SSS");
	
	
	ThreadToRunAtShutdown(long currentTimeMillis)
	{
		try
		{
			File file = new File("data.xml");
			long lastUpdateXML;
			
			// load XML File, create File if it doesn't exist
			if(!file.isFile())
			{
				file.createNewFile();
				lastUpdateXML = System.currentTimeMillis();
				createXML(file, new Date(lastUpdateXML));
			}
			else
			{
				lastUpdateXML = loadDateFromXML(file).getTime();
			}

			SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM");
			
			// convert XML file to ODS if necessary
			if( // new Month has just begun
					Double.parseDouble(sdf.format(new Date(lastUpdateXML)))
					<
					Double.parseDouble(sdf.format(new Date()))
					)
			{
				Counter.saveXMLtoODS(file);
				
				// delete old "data.xml" and create a new one
				file.delete();
				createXML(file, new Date(System.currentTimeMillis()));
			}
			
			
			Date date = new Date();
			
			fTemp = File.createTempFile("data", "xml");
			
			XMLInputFactory inFact = XMLInputFactory.newInstance();
			XMLStreamReader reader = inFact.createXMLStreamReader(new FileInputStream(file));
			
			writer = outFact.createXMLStreamWriter(new FileOutputStream(fTemp));
			
			writer.writeStartDocument();
			reader.next();
			
			writer.writeStartElement("computerzeit");
			reader.next();
			
			writer.writeStartElement("lastUpdated");
			reader.next();
			
			{
				SimpleDateFormat date_complete = new SimpleDateFormat("yyyy MM dd HH:mm:ss.SSS");
				writer.writeCharacters(date_complete.format(date));
				reader.next();
			}
			
			writer.writeEndElement();// END "lastUpdated"
			reader.next();
			
			writer.writeStartElement("rowCount");
			reader.next();
			
			int nrRows = Integer.parseInt(reader.getText());
			writer.writeCharacters(Integer.toString(nrRows + 1));
			reader.next();
			
			writer.writeEndElement();// END "rowCount"
			reader.next();
			
			for(int k = 0; k < nrRows; k++)
			{
				writer.writeStartElement("row" + k);
				reader.next();
				
				// Boot Time
				writer.writeStartElement("boot" + k);
				reader.next();
				
				writer.writeCharacters(reader.getText());
				reader.next();
				
				writer.writeEndElement();// END "boot"
				reader.next();
				
				// Shutdown Time
				writer.writeStartElement("shutdown" + k);
				reader.next();
				
				writer.writeCharacters(reader.getText());
				reader.next();
				
				writer.writeEndElement();// END "shutdown"
				reader.next();
				
				writer.writeEndElement();// END "row"
				reader.next();
				
			}
			
			reader.close();
			
			
			// eigene Spalte
			writer.writeStartElement("row" + nrRows);
			
			writer.writeStartElement("boot" + nrRows);
			writer.writeCharacters(Long.toString(currentTimeMillis));
			writer.writeEndElement();
			
			writer.writeStartElement("shutdown" + nrRows);
		}
		catch(Exception e)
		{
			Counter.saveErrorLog(e, currentTimeMillis);
			System.exit(1);
		}
	}
	
	public void run()
	{
		try
		{
			writer.writeCharacters(Long.toString(System.currentTimeMillis()));
			writer.writeEndElement();
			
			writer.writeEndElement();// END "row" + nrRows
			
			writer.writeEndElement();// END "computerzeit"
			
			writer.writeEndDocument();
			writer.flush();
			writer.close();
			
			// data.xml durch fTemp ersetzen
			file.delete();
			file.createNewFile();
			
			copy(fTemp, file);
			fTemp.deleteOnExit();
		}
		catch (Exception e)
		{
			Counter.saveErrorLog(e, System.currentTimeMillis());
		}
	}

private static long copy(File source, File destination) throws IOException
	{
		long start = System.currentTimeMillis();
		
		source.setReadable(true);
		
		// Eingabedatei öffnen
		FileInputStream eingabeDatei = new FileInputStream(source);
		FileChannel eingabe = eingabeDatei.getChannel();
		
		// Zieldatei öffnen
		RandomAccessFile ausgabeDatei = new RandomAccessFile(destination,"rw");
		FileChannel ausgabe = ausgabeDatei.getChannel(); 
		
		// Memory Mapping durchführen 
		long groeße = eingabe.size(); 
		MappedByteBuffer pufferEin = eingabe.map(FileChannel.MapMode.READ_ONLY, 0, groeße);
		MappedByteBuffer pufferAus = ausgabe.map(FileChannel.MapMode.READ_WRITE, 0, groeße);
		
		// FileChannel können bereits geschlossen sein 
		ausgabeDatei.close();
		eingabeDatei.close();
		
		// kopieren
		while(pufferEin.hasRemaining())
		{
			pufferAus.put(pufferEin.get()); 
		}
		
		long ende = System.currentTimeMillis();
		
		return ende-start;
	}
}

Der Konstruktor des Threads wird noch aufgerufen, aber die run()-Methode scheinbar nicht, sie kommt jedenfalls nicht bis zum Ende.
Was kann ich tun?


Nachtrag:
Führe ich allerdings in der oberen Klasse in der run()-Methode statt wait(); die beiden ausgeblendeten Methoden wait(1200) und System.exit(); auf, so funktioniert alles wie es soll und ich erhalte die gewünschte XML-Datei

Im Anhang: die beiden Klassen komplett als .java -Datei

Mein System:
Windows XP Home SP3 32Bit
JDK + JRE 6u14
 

Anhänge

  • Counter.txt
    6,7 KB · Aufrufe: 34
  • ThreadToRunAtShutdown.txt
    6,7 KB · Aufrufe: 87
Zuletzt bearbeitet:
Ein wait() wartet ja auch unendlich wenn es keinen Trigger bekommt damit aufzuhören. Ein wait(1200) wartet nur maximal 1200 ms.
 
Das wait(); wird ja nur ausgeführt, damit das Programm nicht vor dem herunterfahren des PCs beendet wird, da der Event-Queue "am Ende ist", also nix mehr zu tun hat. Ich könnte genauso einen Thread starten, der ständig irgendwelche Aufgaben ausführt.
Ich werde es mal mit grafischen Komponenten versuchen, dann hat der Event-Queue ja genug zu tun und beendet das Programm nicht von selbst.
 
Also, das Problem lag doch an dem wait();
Ich habe jetzt meinem Programm(das vorher weder GUI noch SystemTrayIcon oder sonstige Objekte mit Listenern hatte)
einfach ein TrayIcon hinzugefügt. irgend ein beliebiger Listener hätte auch den Dienst getan, dass die JVM sich nicht selbst terminiert. Dies wollte ich eigentlich mit dem wait(); bezwecken. Ich wusste jedoch nicht, dass die shutdownhooks nicht ausgeführt werden können, wenn der AWT-Event-Queue blockiert ist.
Danke für die Hilfe
mfg
genodeftest
 

Neue Beiträge

Zurück