9

There is an external program that creates an XML file, but it may take a while to create. I need my Java program to wait until the file exists before moving on.

I've been reading up a little bit about synchronized blocks, and I read that I can do something like this:

synchronized(this) {
    while (!file.exists) { this.wait(); }
}

To be honest I don't really know much about synchronized tasks so I'm wondering if I'm on the right track, or if I'm way off.

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
namxal
  • 101
  • 1
  • 1
  • 7
  • Give some timeout in wait(long timeout); so that after same time thread should wake up. – Prashant Apr 06 '15 at 14:13
  • 5
    No. This is entirely not how this works, forget about `synchronized`. You can either 1) wait for the program to finish, or write something from the program to stdout when the program writes the file; or 2) use a [`WatchService`](http://stackoverflow.com/q/16251273/2071828) to track directory changes. – Boris the Spider Apr 06 '15 at 14:15
  • 1
    Firstly, `synchronized` is related to multithreaded programs. Secondly, external program is running independent of your java program, or your java program launches this external program? – Alexander R. Apr 06 '15 at 14:22
  • The external program is running independent of my java program. – namxal Apr 06 '15 at 14:28
  • 3
    Note that 'exists' and 'completely written' are two different things. You usually can't write files all at once, so you need to check both if the file exists and that the process is no longer writing to it. – Colonel Thirty Two Apr 06 '15 at 14:49

4 Answers4

4

A typical way to solve this problem is for your XML writer to create the XML file, and when it it is done, it should create a second file saying the work is done.

Your java program should listen for the existence of the .done file rather than the XML file.

Won't work if you don't have any control over the XML writing application, though.

user1717259
  • 2,717
  • 6
  • 30
  • 44
0

So what I've gone with is a while loop that checks if the file doesn't exist. If it doesn't, I put the Thread to sleep for one second. It seems to be working correctly. Thank you for the help.

namxal
  • 101
  • 1
  • 1
  • 7
  • 1
    I would recommend that you look into event driven approaches, such as the `WatchService`, rather than the loop-and-poll approach. It will serve you well to move away from arcane and mostly frowned upon habits. – Boris the Spider Apr 08 '15 at 15:57
  • 1
    Ya, I don't like the polling method either. I'l take a look at WatchService. – namxal Apr 08 '15 at 19:39
  • 1
    @namxal Could you provide code for this ? How did you put the Thread to sleep.? – chaviaras michalis Mar 27 '20 at 12:10
0

Use Watch Service API. Part of nio. https://docs.oracle.com/javase/tutorial/essential/io/notification.html

armagedescu
  • 1,758
  • 2
  • 20
  • 31
-3

In my opinion, you should have something to notify the thread. The following is my example.

public class Test {
File file;
public Test(File file){
    this.file = file;
}

public void findFile(){
    synchronized(this){
        while(!file.exists()){
            try {
                System.out.println("before wait:");
                this.wait();
                System.out.println("after wait:");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public void createFile(){
    synchronized(this){
        try {
            System.out.println("before create a new file:");
            file.createNewFile();
            System.out.println("after create a new file:");
            this.notify();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public static void main(String[] args){ 
    Test t = new Test(new File("/Users/yehuizhang/Desktop/uttp.txt"));
    Thread t1 = new Thread(new FindFile(t));
    Thread t2 = new Thread(new CreateFile(t));
    t1.start();
    t2.start();
}
}

class FindFile implements Runnable{
Test t;
public FindFile(Test t){
    this.t = t;
}

@Override
public void run(){
    t.findFile();
}
}

class CreateFile implements Runnable{
Test t;

public CreateFile(Test t){
    this.t = t;
}

@Override
public void run(){
    t.createFile();
}
}
uttp
  • 92
  • 6
  • @ColonelThirtyTwo Thirty Two no it works well. The result is `before wait: before create a new file: after create a new file: after wait:` – uttp Apr 06 '15 at 14:55
  • 1
    Wait on what? `createFile` is in an external program, and can't notify the `findFile` thread. – Colonel Thirty Two Apr 06 '15 at 14:58
  • @ColonelThirtyTwo When the two threads use an `Test` instance, `createFile` can notice the `findFile`. You have't understand my code. – uttp Apr 07 '15 at 01:01
  • What I'm saying is that your code isn't representative of the problem. The OP said in the first sentence of his question is that the file is created in an _external process_, which can't use `Object.notify`. – Colonel Thirty Two Apr 07 '15 at 02:03