• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

About RandomAccessFile

 
Arto Pastinen
Ranch Hand
Posts: 79
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 21
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 79
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 21
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 79
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 79
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
.. 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
Posts: 21
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 79
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 21
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 79
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 1646
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic