How do I use one Java program, to monitor another Java program's output?

后端 未结 3 1662
一整个雨季
一整个雨季 2021-01-01 08:03

Below is diagram that shows what I\'m trying to do : it is just 2 programs. One is a simple Child program that writes out integers every 2 seconds, line-by-line

相关标签:
3条回答
  • 2021-01-01 08:18

    You can use the directory watch service:

    https://docs.oracle.com/javase/tutorial/essential/io/notification.html

    You can configure a path or a file and register a watcher.

    The watcher gets a notification every time a file is changed. You can store this timestamp of a notification for later use.

    For details see my link above.

    You may then use a Timer or a Thread to check last modification.

    0 讨论(0)
  • 2021-01-01 08:30

    While your method of creating a text file, and using a batch script is feasible, there is a better way to approach it. This is a standard problem to approach with multitasking, and by creating a couple threads, it is not too difficult at all.

    Using threads has several advantages over going externally "around" the system with batch files and multiple programs. For starters, these may include:

    1. Keeping everything together makes the project much tidier, cleaner, and marginally easier to distribute.

    2. It is easier to implement. Sure threads may seem confusing if you have never used them, but they are the lesser evil in my opinion, then all the steps involved in going around them. As I hope to show below, implementing this problem with threads is not hard.

    3. Improved performance, as the very expensive operations of file IO, and spawning the batch file are avoided. Threads also have improved performance over processes in most cases because they are easier to spawn, and multithreading sees performance improvements on a wider range of processors than multiprocessing by being less reliant on having several cores.

    4. No sketchy overlap between when one program is reading the file, while the other is writing to it simultaneously. These kind of situations are best avoided when possible.

    5. Maintains Java's impressive cross platform abilities, because you are not using batch which is not cross platform. This might not be important to you for this project, but you may come across something in the future with a similar problem, where this is more important, and so you will have practice implementing it.

    6. You learn better by using threads the "right way" instead of developing bad habits by using a more hacky approach. If this is a learning project, you might as well learn it right.

    I went ahead and coded up the approach that I would most likely use to solve the problem. My code has a child thread the counts every two seconds, and a parent thread that monitors the child, and restarts it if the child goes five seconds without counting. Let's examine my program to give you a good idea of how it is working.

    First, here is the class for the parent:

    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();
        }
    
    }
    

    The main function in there can be put somewhere else if you want, but to start everything up, just instantiate a parent. The parent class has an instance of the child class, and it starts up the child thread. The child will report it's counting to the parent with the report method, which spawns a watchdog timer (more on that in a second) that will call restartChild after five seconds with the current count. RestartChild, restarts the child thread, if the count is still the same as the one provided.

    Here is the class for the watchdog timer:

    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 ();
              }
           }
    
        }
    

    This watchdog timer is a thread that the parent will run with the start method. The parent sends itself as a parameter so that we can call the restartChild function of the parent.It stores the count, because when it runs after five seconds, restartChild will check if the count has changed.

    And finally, here is the child class

    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;
        }
    
    
    }
    

    This is also a thread, thus it implements runnable, and in that regard acts a lot like the watchdog. Run() is the main method of the child thread, this is where your logic goes that gets called when you start it. Starting the child with start() sets all the variables to their defaults, and then begins the run() logic. The logic in run is wrapped in if(running), because that lets us kill the thread internally by setting running to false.

    Currently, all the child does right now is increment it's counter, output it to console, and then report the activity to the parent, 100 times, every two seconds. You will likely want to remove the condition stopping it after count passes 100, but I included it, so that the parent would eventual have cause to restart the child. To change the behavior, look at the child's run method, that is where all the main action is at.

    0 讨论(0)
  • 2021-01-01 08:45

    This will get very slow as the file keeps growing in size. A simpler way would be to simply check the last modification time of the file. Assuming that the reason the child program might stop writing to the file is that the program terminates (rather than e.g. hanging in an infinite loop), it is probably better to directly monitor the child process itself rather than relying on observing the effects of the process. This is particularly convenient if the parent process can be responsible for starting the program in the first place.

    This can be done with the ProcessBuilder and Process classes in Java 8. Copying from the documentation, you can start the process like this (if you only want to monitor whether it's running or not):

    ProcessBuilder pb = new ProcessBuilder("TheBatchFile.bat", "Argument1", "Argument2");
    pb.directory(new File("/path/to/working/dir"));
    Process p = pb.start();
    

    Then, you can simply call p.waitFor(); to wait for the process to terminate. Do this in a loop, and you have your automatic-restarting-of-child behavior.

    0 讨论(0)
提交回复
热议问题