在Java对象上同步文件访问 [英] File access synchronized on Java object

查看:130
本文介绍了在Java对象上同步文件访问的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个对象负责将JTable状态持久化到磁盘.它保存/加载可见列,它们的大小,位置等.下面是其类定义中的一些有趣的内容.

I have an object responsible for persisting JTable state to disk. It saves/loads visible columns, their size, position etc. A few interesting bits from its class definition are below.

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 ... finally关闭流.
    • There only exists one instance of TableSaver, ever.
    • load() can be called from many threads. Timer clearly is another thread.
    • loadFile() and writeFile() do not leave open file streams - they use a robust, well tested and broadly used library which always closes the streams with try ... finally.
    • 有时这会失败,并出现以下异常:

      Sometimes this fails with an exception like:

      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
      

      所以我有两个问题:

      1. 这种同步如何失败?请注意,我确定只有TableSaver的一个实例.
      2. 堆栈跟踪中的这是什么:package.TableSaver.access$600(TableSaver.java:34)?第34行是带有class TableSaver {的行.这可能是同步无法正常工作的原因吗?
      1. How can this kind of synchronization fail? Note that I am sure there only is one instance of TableSaver.
      2. What is this thing in the stacktrace: package.TableSaver.access$600(TableSaver.java:34)? Line 34 is the line with class TableSaver {. Can this be the reason why the synchronization is not working?

      推荐答案

      错误6354433 的摘录:

      Google learns me that this seems to be Windows specific. Here's an extract of Bug 6354433:

      这是Windows平台问题,具有内存映射文件,即MappedByteBuffer. FileChannel的Java 5.0文档指出在缓冲区被垃圾回收之前,缓冲区及其表示的映射将保持有效".当我们尝试重新打开文件存储并且映射的字节缓冲区未经过GC时,将发生错误.由于没有用于映射字节缓冲区的unmap()方法(请参见错误4724038),因此当释放缓冲区时,我们将受底层操作系统的摆布.调用System.gc()可能会释放缓冲区,但不能保证.在Solaris上不会发生此问题.可能是由于在Solaris上实现共享内存的方式.因此,Windows的解决方法是不要将内存映射文件用于事务信息表.

      This is Windows platform issue with memory-mapped file, i.e. MappedByteBuffer. The Java 5.0 doc for FileChannel 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 no unmap() 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. Calling System.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版本?它有最新的更新吗?

      What Java/Windows version are you using? Does it have the latest updates?

      还有另外两个相关的错误,并提供了一些有用的见解:

      Here are two other related bugs with some useful insights:

      • Bug 4715154 - Memory mapped file cannot be deleted.
      • Bug 4469299 - Memory mapped files are not GC'ed.

      关于第二个问题,那只是内部或匿名类的自动生成的类名.

      As to your second question, that's just the autogenerated classname of an inner or anonymous class.

      这篇关于在Java对象上同步文件访问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆