Granny's Programming Pearls
"inside of every large program is a small program struggling to get out"
JavaRanch.com/granny.jsp
The moose likes Java in General and the fly likes About RandomAccessFile Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of OCM Java EE 6 Enterprise Architect Exam Guide this week in the OCMJEA forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "About RandomAccessFile" Watch "About RandomAccessFile" New topic
Author

About RandomAccessFile

Arto Pastinen
Ranch Hand

Joined: Dec 13, 2002
Posts: 79
Is there some ThreadLocal variables in RandomAccessFile, because following won't do nothing:

final RandomAccessFile raf = new RandomAccessFile(f, "rws");
Thread t = new Thread() {
public void run() {
try {
raf.write("test".getBytes("ascii"));
}
catch(Throwable t) {
t.printStackTrace();
}
}
};
raf.close();

.. but if i do write in Thread, which creates RandomAccessFile instance, then it works.. I don't get any exceptions, and i didn't see anything in api which could explain this.
Simon Birch
Greenhorn

Joined: Dec 26, 2003
Posts: 21
I think what is happening here is that you are creating a Thread object with your own run method. But you never call any methods on the Thread object, so the code you have in the run method is never executed.

You need to call the start() method on Thread in order to execute the code in the run() method in a seperate thread.
Arto Pastinen
Ranch Hand

Joined: Dec 13, 2002
Posts: 79
ah yes.. but still it won't work. i will get following exception:

java.io.IOException: Bad file descriptor
at java.io.RandomAccessFile.writeBytes(Native Method)
at java.io.RandomAccessFile.write(RandomAccessFile.java:435)
at test.Main$1.run(Main.java:20)

.. and if do write in original thread, it works fine!

btw. That exception was original problem i just wrote that test code for this forum..
[ February 11, 2005: Message edited by: Arto Pastinen ]
Simon Birch
Greenhorn

Joined: Dec 26, 2003
Posts: 21
In that case, I would look at the object referred to by 'f'. The file name may be mangled in some way. Can you access the file through f? What do you get if you try


That might help zero in on the problem.
Arto Pastinen
Ranch Hand

Joined: Dec 13, 2002
Posts: 79
That is no problem.

Here is all testing code (i added that Thread.start()):

public class Main {
public static void main(String args[]) throws Throwable {
File f = new File("/tmp/test");
if(f.exists()) f.delete();
f.createNewFile();

final RandomAccessFile raf = new RandomAccessFile(f, "rws");
Thread t = new Thread() {
public void run() {
try {
raf.write("test".getBytes("ascii"));
}
catch(Throwable t) {
t.printStackTrace();
}
}
};
t.start();
raf.close();
}
}
Arto Pastinen
Ranch Hand

Joined: Dec 13, 2002
Posts: 79
.. and if i make raf.write(..) in original main thread, it works.
But it won't work if i try to seek/write/do something in different thread.

I think that this is a bug in JVM. I check sources of RandomAccessFile, and i found followings:

public void write(byte b[]) throws IOException {
writeBytes(b, 0, b.length);
}

public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len);
}

/**
* Writes a sub array as a sequence of bytes.
* @param b the data to be written

* @param off the start offset in the data
* @param len the number of bytes that are written
* @exception IOException If an I/O error has occurred.
*/
private native void writeBytes(byte b[], int off, int len) throws IOException;

.. and after fast testing, it seems to be at least these versions:

Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_06-b03)
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_01-b08)

Native enviroment is Linux Debian sarge, kernel 2.6
[ February 11, 2005: Message edited by: Arto Pastinen ]
Simon Birch
Greenhorn

Joined: Dec 26, 2003
Posts: 21
I've done some experimenting. The problem you are having is caused by seperating the file writing and closing into different threads.

After the t.start(), the JVM will be executing two threads - one is your code in the run method, the other is the code folloing on from where you called start(). These two threads of execution have no guarantees about the order in which they will be processed, or about when one thread might be stopped and the other started.

I guess what you are experiencing is the JVM completing the raf.close() before it gets to the raf.write().

How to solve this depends on what you are trying to achieve. Do you actually NEED to use a sperate thread?

If not, the following might be a better approach (I'm using windows, so I've changed the file name for ease):
Arto Pastinen
Ranch Hand

Joined: Dec 13, 2002
Posts: 79
Nice.. You rock Simon. Thanks. =)

i added this code to test code, and after that it works.

...
t.start();

while(t.isAlive()) {
System.out.println("Main.main() waiting...");
Thread.yield();
}
raf.close();
...

I was implementing somekind download service where we download same file from multiple sources.. well.. now things will start to go painful..

[ February 11, 2005: Message edited by: Arto Pastinen ]
Simon Birch
Greenhorn

Joined: Dec 26, 2003
Posts: 21
Glad you got the code going Arto, but I'd really think about either not using the Thread or putting all the file handling into the Thread code.
Arto Pastinen
Ranch Hand

Joined: Dec 13, 2002
Posts: 79
i think that i will make one thread more, which handles file writing, and there is somekind container where download thread's pushes blocks, and writer thread pop these blocks and write to file.
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Unless I'm mistaken, as long as you ensure that each thread is writing do different parts of the same file, there should be no problem in havnig each Thread maintain its own RandomAccessFile. Actually, I'd recommend putting the RAF-handling behind an abstraction class, say ChunkedDownloadFile (totally made up; pick something better).

The main program would create a CDF with a filename and a Set/List of sources from which to download. Next it creates a Thread for each source (though if you switch to NIO from JDK 1.4 you can do this without a lot of threads) and gives it the CDF.

The CDF would be responsible for choosing the next chunk when a download thread asks for it. The thread would manage its own RAF to write to the main file but keep the CDF informed as each chunk is completed. Actually, the CDF could maintain the RAFs I suppose using ThreadLocal. I'd draw it out and see what makes more sense.

One other piece of advice: use Runnable implementations rather than subclass Thread. The former is designed for this case where you want to give a task to a Thread to run. You should only extend Thread if you need to alter Thread's behavior, which you're not doing here. This was discussed in the Threads forum recently.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: About RandomAccessFile