class TableSaver { Timer timer = new Timer(true); TableSaver() { timer.schedule(new TableSaverTimerTask(),15000,SAVE_STATE_PERIOD); } synchronized TableColumns load(PersistentTable table) { String xml = loadFile(table.getTableKey()); // parse XML,return } synchronized void save(String key,TableColumns value) { try { // Some preparations writeFile(app.getTableConfigFileName(key),xml); } catch (Exception e) { // ... handle } } private class TableSaverTimerTask extends TimerTask { @Override public void run() { synchronized (TableSaver.this) { Iterator<PersistentTable> iterator = queue.iterator(); while (iterator.hasNext()) { PersistentTable table = iterator.next(); if (table.getTableKey() != null) { save(table.getTableKey(),dumpState(table)); } iterator.remove(); } } } } }
>只存在一个TableSaver实例.
> load()可以从很多线程调用.计时器显然是另一个线程.
> loadFile()和writeFile()不会留下打开的文件流 – 它们使用一个健壮,经过良好测试和广泛使用的库,最终通过try …关闭流.
有时这样会失败,例如:
java.lang.RuntimeException: java.io.FileNotFoundException: C:\path\to\table-MyTable.xml (The requested operation cannot be performed on a file with a user-mapped section open) at package.FileUtil.writeFile(FileUtil.java:33) at package.TableSaver.save(TableSaver.java:175) at package.TableSaver.access$600(TableSaver.java:34) at package.TableSaver$TableSaverTimerTask.run(TableSaver.java:246) at java.util.TimerThread.mainLoop(Unknown Source) at java.util.TimerThread.run(Unknown Source) Caused by: java.io.FileNotFoundException: C:\path\to\table-MyTable.xml (The requested operation cannot be performed on a file with a user-mapped section open) at java.io.FileOutputStream.open(Native Method) at java.io.FileOutputStream.<init>(Unknown Source) at java.io.FileOutputStream.<init>(Unknown Source) at package.FileUtilWorker.writeFile(FileUtilWorker.java:57) ... 6 more
所以我有两个问题:
>这种同步怎么会失败?请注意,我确定只有一个TableSaver实例.
> stacktrace中的这些东西是什么?package.TableSaver.access $600(TableSaver.java:34)?第34行是与类TableSaver {的行.这可能是同步不行的原因吗?
解决方法
This is Windows platform issue with memory-mapped file,i.e.
MappedByteBuffer
. The Java 5.0 doc forFileChannel
state that “the buffer and the mapping that it represents will remain valid until the buffer itself is garbage-collected”. The error occurs when we tried to re-open the filestore and the mapped byte buffer has not been GC. Since there is nounmap()
method for mapped byte buffer (see bug 4724038),we’re at the mercy of the underlying operating system on when the buffer get free up. CallingSystem.gc()
might free up the buffer but it is not guarantee. The problem doesn’t occurs on Solaris; may be due to the way shared memory is implemented on Solaris. So the work-around for Windows is not to use memory-mapped file for the transaction information tables.
你使用什么Java / Windows版本?它有最新的更新吗?
这里有两个相关的错误,有一些有用的见解:
> Bug 4715154 – 无法删除内存映射文件.
> Bug 4469299 – 内存映射文件未GC.