patternjavaMinor
Optimizing a thread safe Java NIO / Serialization / FIFO Queue
Viewed 0 times
niofifoserializationjavathreadoptimizingsafequeue
Problem
I've written a thread safe, persistent FIFO for
The problem is it isn't fast enough. Most of it is undoubtedly due to reading and writing directly to disk but I think we should be able to squeeze a bit more out of it anyway. Any ideas on how to improve the performance of the 'take'- and 'add'-methods?
```
/**
* DiskQueue Persistent, thread safe FIFO queue for
* Serializable items.
*/
public class DiskQueue
{
public static final int EMPTY_OFFS = -1;
public static final int LONG_SIZE = 8;
public static final int HEADER_SIZE = LONG_SIZE * 2;
private InputStream inputStream;
private OutputStream outputStream;
private RandomAccessFile file;
private FileChannel channel;
private long offs = EMPTY_OFFS;
private long size = 0;
public DiskQueue(String filename)
{
try
{
boolean fileExists = new File(filename).exists();
file = new RandomAccessFile(filename, "rwd");
if (fileExists)
{
size = file.readLong();
offs = file.readLong();
}
else
{
file.writeLong(size);
file.writeLong(offs);
}
} catch (FileNotFoundException e)
{
throw new RuntimeException(e);
} catch (IOException e)
{
throw new RuntimeException(e);
}
channel = file.getChannel();
inputStream = Channels.newInputStream(channel);
outputStream = Channels.newOutputStream(channel);
}
/**
* Add item to end of queue.
*/
public void add(ItemT item)
{
try
{
synchronized (this)
{
channel.position(channel.size());
ObjectOutputStream s = new ObjectOutputStream(outputStream);
s.writeObject(item);
s.flush();
size++;
Serializable items. The reason for reinventing the wheel is that we simply can't afford any third party dependencies in this project and want to keep this really simple. The problem is it isn't fast enough. Most of it is undoubtedly due to reading and writing directly to disk but I think we should be able to squeeze a bit more out of it anyway. Any ideas on how to improve the performance of the 'take'- and 'add'-methods?
```
/**
* DiskQueue Persistent, thread safe FIFO queue for
* Serializable items.
*/
public class DiskQueue
{
public static final int EMPTY_OFFS = -1;
public static final int LONG_SIZE = 8;
public static final int HEADER_SIZE = LONG_SIZE * 2;
private InputStream inputStream;
private OutputStream outputStream;
private RandomAccessFile file;
private FileChannel channel;
private long offs = EMPTY_OFFS;
private long size = 0;
public DiskQueue(String filename)
{
try
{
boolean fileExists = new File(filename).exists();
file = new RandomAccessFile(filename, "rwd");
if (fileExists)
{
size = file.readLong();
offs = file.readLong();
}
else
{
file.writeLong(size);
file.writeLong(offs);
}
} catch (FileNotFoundException e)
{
throw new RuntimeException(e);
} catch (IOException e)
{
throw new RuntimeException(e);
}
channel = file.getChannel();
inputStream = Channels.newInputStream(channel);
outputStream = Channels.newOutputStream(channel);
}
/**
* Add item to end of queue.
*/
public void add(ItemT item)
{
try
{
synchronized (this)
{
channel.position(channel.size());
ObjectOutputStream s = new ObjectOutputStream(outputStream);
s.writeObject(item);
s.flush();
size++;
Solution
A big performance killer in your code is the use of
A quick benchmark gives me a 500x speed improvement just by removing the
You should remove this
"rwd" mode to open the file. The "d" forces every write to be synchronously written on the physical disk.A quick benchmark gives me a 500x speed improvement just by removing the
"d" in your code. I did a profiling of your code, and it appears that the majority of the time is spent in the writeLong function. This is because writeLong internally calls write eight times, and each time a physical write is performed !You should remove this
"d" mode and insert flushing instructions at strategic places. I think FileChannel.force(false) is the right method for that. Adding this instruction in add, take and defrag gives me a 12x speed improvement compared to the original code.Context
StackExchange Code Review Q#17870, answer score: 4
Revisions (0)
No revisions yet.