programación - libro de programacion en java netbeans pdf
¿Cómo uso un programa Java para monitorear el resultado de otro programa Java? (3)
Esto se hará muy lento a medida que el archivo siga creciendo en tamaño. Una forma más simple sería simplemente verificar la última modificación del tiempo del archivo. Asumiendo que la razón por la cual el programa hijo podría dejar de escribir en el archivo es que el programa termina (en lugar de, por ejemplo, colgando en un bucle infinito), probablemente sea mejor monitorear directamente el proceso hijo en lugar de confiar en observar los efectos del proceso . Esto es particularmente conveniente si el proceso principal puede ser responsable de iniciar el programa en primer lugar.
Esto se puede hacer con las clases ProcessBuilder y Process en Java 8. Al copiar de la documentación, puede iniciar el proceso de esta manera (si solo desea controlar si se está ejecutando o no):
ProcessBuilder pb = new ProcessBuilder("TheBatchFile.bat", "Argument1", "Argument2");
pb.directory(new File("/path/to/working/dir"));
Process p = pb.start();
Entonces, simplemente puede llamar a p.waitFor();
esperar a que el proceso finalice. Haga esto en un bucle, y tendrá su comportamiento de reinicio automático del niño.
A continuación se muestra un diagrama que muestra lo que estoy tratando de hacer: son solo 2 programas. Uno es un programa Child
simple que escribe enteros cada 2 segundos, línea por línea.
El otro es un programa para Parent
que supervisa el archivo de registro (solo un archivo de texto muy básico). Si el archivo de registro no se modifica en 5 segundos, entonces debe reiniciar el programa Child
(a través de un archivo por lotes); luego continúa normalmente.
Mi código para la clase infantil está aquí:
package fileiotestapplication;
import java.io.*;
import java.io.IOException;
import java.util.*;
public class WriterClass {
@SuppressWarnings("oracle.jdeveloper.java.insufficient-catch-block")
public WriterClass() {
super();
int[] content = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,};
String[] friends = {"bob",};
File file = new File("/C:/Java_Scratch/someFile.txt");
// if file does not exists, then create it
try {
if (!file.exists()) {
file.createNewFile();
}
for (int i = 0 ; i < content.length; i++)
{
PrintStream bw = new PrintStream( new FileOutputStream(file, true) );
System.out.println("testing " + i);
bw.println( String.valueOf(content[i]) );
bw.close();
Thread.sleep(2500);
}
System.out.println("Done");
} catch (IOException ioe) {
// TODO: Add catch code
ioe.printStackTrace();
}
catch (InterruptedException ioe) {
// TODO: Add catch code
ioe.printStackTrace();
}
//someIS.println(i);
System.out.println("This is OK");
}
public static void main(String[] args) {
WriterClass writerClass = new WriterClass();
}
}
Y vinculé aquí mi código actual para la clase de Padres .
Lo que intento hacer ahora es agregar alguna lógica que capte cuando la clase hija deja de escribir el resultado. Lo que me gustaría hacer es contar todas las líneas en el archivo de registro; y luego compararlos cada 5 segundos, ¿es esta una buena manera (la alternativa sería - seguir comprobando para ver si el archivo se modificó en absoluto)?
EDITAR: La sugerencia a continuación para usar waitFor()
hecho ayuda, aunque todavía estoy trabajando en los detalles: en general es como:
try {
/* StackOverflow code */
for ( ; ; ) {
ProcessBuilder pb = new ProcessBuilder("TheBatchFile.bat");
pb.directory(new File("C://Java_Scratch_//Autonomic_Using_Batch//"));
Process p = pb.start();
p.waitFor();
}
/* end - StackOverflow code */
}
catch (IOException i) {
i.printStackTrace();
}
catch (InterruptedException i) {
i.printStackTrace();
}
Puede usar el servicio de vigilancia de directorio:
https://docs.oracle.com/javase/tutorial/essential/io/notification.html
Puede configurar una ruta o un archivo y registrar un watcher
.
El observador recibe una notificación cada vez que se cambia un archivo. Puede almacenar esta marca de tiempo de una notificación para su uso posterior.
Para detalles, mira mi enlace de arriba.
Luego puede usar un temporizador o un hilo para verificar la última modificación.
Si bien su método para crear un archivo de texto y usar un script por lotes es factible, existe una mejor manera de abordarlo. Este es un problema estándar para abordar con la multitarea, y al crear un par de hilos, no es demasiado difícil en absoluto.
El uso de subprocesos tiene varias ventajas sobre ir "alrededor" del sistema externamente con archivos por lotes y múltiples programas. Para empezar, estos pueden incluir:
Mantener todo junto hace que el proyecto sea mucho más ordenado, más limpio y marginalmente más fácil de distribuir.
Es más fácil de implementar. Claro que los hilos pueden parecer confusos si nunca los has usado, pero en mi opinión son el mal menor, y luego todos los pasos necesarios para sortearlos. Como espero mostrar a continuación, implementar este problema con hilos no es difícil.
Se evita el rendimiento mejorado, ya que se evitan las costosas operaciones del archivo IO y el desove del archivo por lotes. Los subprocesos también han mejorado el rendimiento de los procesos en la mayoría de los casos porque son más fáciles de generar, y el multithreading ve las mejoras de rendimiento en una gama más amplia de procesadores que el multiproceso al ser menos dependiente de tener varios núcleos.
No hay superposición incompleta entre cuando un programa está leyendo el archivo, mientras que el otro está escribiendo en él simultáneamente. Este tipo de situaciones es mejor evitarlas cuando sea posible.
Mantiene las impresionantes capacidades de plataforma cruzada de Java, porque no está utilizando lotes que no son multiplataforma. Puede que esto no sea importante para este proyecto, pero puede que encuentre algo en el futuro con un problema similar, donde esto es más importante, por lo que tendrá práctica para implementarlo.
Usted aprende mejor al utilizar los hilos de la "manera correcta" en lugar de desarrollar malos hábitos mediante el uso de un enfoque más hacky. Si se trata de un proyecto de aprendizaje, es mejor que lo aprenda bien.
Seguí adelante y codifiqué el enfoque que probablemente utilizaría para resolver el problema. Mi código tiene un hilo hijo los recuentos cada dos segundos y un hilo padre que supervisa al niño y lo reinicia si el niño pasa cinco segundos sin contar. Examinemos mi programa para darle una buena idea de cómo está funcionando.
Primero, aquí está la clase para el padre:
public class Parent {
private Child child;
public Parent(){
child = new Child(this);
child.start();
}
public void report(int count){ //Starts a new watchdog timer
Watchdog restartTimer = new Watchdog(this, count);
restartTimer.start();
}
public void restartChild(int currentCount){
if (currentCount == child.getCount()){ //Check if the count has not changed
//If it hasn''t
child.kill();
child.start();
}
}
public static void main(String[] args){
//Start up the parent function, it spawns the child
new Parent();
}
}
La función principal allí puede colocarse en otro lugar si lo desea, pero para comenzar todo, solo instale un padre. La clase principal tiene una instancia de la clase secundaria e inicia el subproceso secundario. El niño informará que está contando al padre con el método de informe, que genera un temporizador de vigilancia (más sobre eso en un segundo) que llamará a restartChild después de cinco segundos con el recuento actual. RestartChild, reinicia el hilo hijo, si el recuento sigue siendo el mismo que el proporcionado.
Aquí está la clase para el temporizador de vigilancia:
class Watchdog implements Runnable { //A timer that will run after five seconds
private Thread t;
private Parent parent;
private int initialCount;
public Watchdog(Parent parent, int count){ //make a timer with a count, and access to the parent
initialCount = count;
this.parent = parent;
}
public void run() { //Timers logic
try {
Thread.sleep(5000); // If you want to change the time requirement, modify it here
parent.restartChild(initialCount);
} catch (InterruptedException e) {
System.out.println("Error in watchdog thread");
}
}
public void start () // start the timer
{
if (t == null)
{
t = new Thread (this);
t.start ();
}
}
}
Este temporizador de vigilancia es un hilo que el padre ejecutará con el método de inicio. El padre se envía a sí mismo como un parámetro para que podamos llamar a la función restartChild del padre. Almacena el recuento, porque cuando se ejecuta después de cinco segundos, restartChild comprobará si el recuento ha cambiado.
Y finalmente, aquí está la clase infantil
public class Child implements Runnable{
private Thread t;
public int counter = 0;
private boolean running;
private Parent parent; // Record the parent function
public Child(Parent parent){
this.parent = parent;
}
private void initializeAll(){
counter = 0;
running = true;
}
public int getCount(){
return counter;
}
@Override
public void run() {
while((counter <= 100)&&(running)){
//The main logic for child
counter +=1;
System.out.println(counter);
parent.report(counter); // Report a new count every two seconds
try {
Thread.sleep(2000); // Wait two seconds
} catch (InterruptedException e) {
System.out.println("Thread Failed");
}
}
}
public void start(){ //Start the thread
initializeAll();
t = new Thread(this);
t.start();
}
public void kill(){ //Kill the thread
running = false;
}
}
Esto también es un hilo, por lo que implementa ejecutable, y en ese sentido actúa de manera muy similar al perro guardián. Run () es el método principal del subproceso secundario, aquí es donde va tu lógica que se llama cuando lo inicias. Al iniciar el elemento secundario con start () se establecen todas las variables a sus valores predeterminados, y luego comienza la lógica de ejecución (). La lógica en ejecución está envuelta en if (en ejecución), porque eso nos permite eliminar el hilo internamente estableciendo la ejecución en falso.
Actualmente, todo lo que hace el niño en este momento es incrementar su contador, enviarlo a la consola y luego informar la actividad al padre, 100 veces, cada dos segundos. Es probable que desee eliminar la condición de detenerlo después de que el recuento pase 100, pero lo incluí, por lo que el padre eventualmente tendría motivos para reiniciar el niño. Para cambiar el comportamiento, observe el método de ejecución del niño, que es donde está toda la acción principal.