6

这个问题似乎很常见,但是当多线程写入同一个文件(Excel)时我遇到了问题。这是我的代码:

public class XLWriter {

private XLWriter() {
}

private static class SingletonHelper {
    private static final XLWriter INSTANCE = new XLWriter();
}

public static synchronized XLWriter getInstance() {
    return SingletonHelper.INSTANCE;
}

public static synchronized void writeOutput(Map<String, String> d) {
    try {
        --- Write file
    } catch (Exception e) {
        SOP("Not able to write output to the output file.");
    }
}

public static void createWorkBook(String fileName, String sheetName)
        throws IOException {
    try {
        -- Create workbook
    } catch (WriteException e) {
        System.out.println("Could not create workbook" + e);
    }
}

我正在使用 testng 框架,并且 10 个线程尝试写入同一个文件。许多线程无法写入它并进入异常块......有什么更好的方法来做到这一点?任何代码示例都会对我有很大帮助,因为我完成这个的时间非常少。谢谢。

4

1 回答 1

6

您不需要同步纯读取,因此public static synchronized XLWriter getInstance()可以synchronized没有任何错误。您只需要同步写入,其中多个线程可能同时写入/读取相同的数据。

有两件事可以解决您的问题。最简单的方法是创建一个特殊的写入函数,然后它是唯一要同步的函数:

private void write(final File f, final Map<String, String> output) {
  synchronized(f) {
    // do the write
  }
}

在 f 上同步是正确的,因为这是必须以独占方式访问的共享资源。

只要您告诉文件创建不要覆盖现有文件,就不需要更改 createWorkBook 函数,因为文件系统本身已经是线程安全的。现在您只需要一个已打开文件的查找表来获取适当的文件句柄,因为在任何时候打开的每个文件都必须只有一个文件。这可以使用像这样的 ConcurrentHashMap 来解决:

public void getFileFor(String filename) {
  File newFile = File(filename);
  File inList = fileHashMap.putIfAbsent(newFile);
  if (inList != null) {
    return inList;
  } else {
    return newFile;
  }
}

只要确保你有一个解决方案,一旦你完成了关闭哈希图中的所有文件。

如需进一步的想法:您也可以创建一个写入线程,其唯一目的是将内容写入该文件。如果这个线程有一个ConcurrentBlockingQueue,其他线程可以将他们的部分而不是文件添加到这个队列中,然后继续他们正在做的任何事情,而写线程是唯一可以访问文件的人。因此不会出现写问题,线程安全完全由 ConcurrentBlockingQueue 处理。

于 2013-11-11T13:55:12.467 回答