java - 在字符串方法参数上同步java中的io操作?

yan*_*nko 2 java io multithreading synchronization

基本上,我有一个包含 2 个方法的类:一个将对象序列化为 XML 文件,另一个从 XML 读取对象。以下是恢复对象的方法中同步部分的示例:

    public T restore(String from) throws Exception {
     // variables declaration
        synchronized (from) {
            try {
                decoder = new XMLDecoder(new BufferedInputStream(
                        new FileInputStream(from)));
                restoredItem = decoder.readObject();
                decoder.close();
            } catch (Exception e) {
                logger.warning("file not found or smth: " + from);
                throw new Exception(e);
            }
        }
    // try to cast it
    }
Run Code Online (Sandbox Code Playgroud)

序列化对象时采用类似的方法。现在,当我创建一个单元测试时,它依次创建 10 个线程,每个线程尝试序列化并立即读取布尔值或字符串,它会失败,显示发生 ClassCastExceptions。这让我觉得我的序列化是错误的(在单线程环境中一切正常)。如果你一直和我在一起:),这里有两个我需要你帮助的问题:

  1. 在传递给方法的字符串参数上进行同步是否有意义(考虑到 java 中有一个字符串池)?顺便说一句,我试过同步 XMLSerializer 类本身,结果保持不变。
  2. 如何正确同步单个文件上的 io 操作?

Ran*_*ron 5

1. 是的,可以在字符串上同步,但是您需要在字符串上同步。实习生()为了始终获得相同的对象

StringBuffer sb = new StringBuffer(); sb.append("a").append("b");
String a = new String(sb.toString());
String b = new String(sb.toString());
a == b; //false
a.equals(b); //true
a.intern() == b.intern(); //true
Run Code Online (Sandbox Code Playgroud)

由于您想在同一个监视器上同步,因此您需要 intern()。

2. 您可能不想在 String 上进行同步,因为它可能会在其他地方、您的代码内部、第 3 方或 JRE 中同步。如果我想保持同步,我会做的是创建一个 ID 类(它可能只包含字符串),覆盖 equals() 和 hashcode() 以匹配,将它放在一个 WeakHashMap 中,同时作为键和值(请参阅 IdentityHashMap 了解原因)并仅使用我从地图中获取的内容(sync map{ syncKey = map.get(new ID(from)); if syncKey==null create and put new key} sync{syncKey} )。

3. 再说一次,我将全部同步并使用 java.util.concurrent.locks.Lock 代替,在与上述相同的设置中,仅将锁附加到 ID。