我正在开发一个小型Web应用程序,其Servlet定期访问共享资源,该资源是服务器端包含一些可变数据行的简单文本文件。在大多数情况下,servelt只是读取文件中的数据,但是某些servelt可能还会更新它,在文件中添加新行,或者删除并替换现有行。尽管文件内容不是很经常更新,但是如果两个或多个Servlet决定同时读写文件,则数据不一致和文件损坏的可能性仍然很小。
首要目标是确保文件读写的安全性。为此,我创建了一个帮助程序FileReaderWriter类,提供了一些用于线程安全文件访问的静态方法。读取和写入方法由ReentrantReadWiteLock
协调。规则很简单:只要没有其他线程同时写入文件,多个线程就可以随时从文件中读取。
public class FileReaderWriter {
private static final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
public static List<String> read(Path path) {
List<String> list = new ArrayList<>();
rwLock.readLock().lock();
try {
list = Files.readAllLines(path);
} catch (IOException e) {
e.printStackTrace();
} finally {
rwLock.readLock().unlock();
}
return list;
}
public static void write(Path path, List<String> list) {
rwLock.writeLock().lock();
try {
Files.write(path, list);
} catch (IOException e) {
e.printStackTrace();
} finally {
rwLock.writeLock().unlock();
}
}
}
然后,每个Servlt都可以使用上述方法读取文件,如下所示:
String dataDir = getServletContext().getInitParameter("data-directory");
Path filePath = Paths.get(dataDir, "test.txt");
ArrayList<String> list = FileReaderWriter.read(filePath);
类似地,可以使用FileReaderWriter.write(filePath, list)
方法进行写入。注意:如果需要替换或删除某些数据(这意味着从文件中获取数据,对其进行处理并将更新后的数据写回到文件中),则此操作的整个代码路径应由rwLock.writeLock()
锁定,以确保原子性原因。
现在,当访问共享文件似乎很安全(至少,我希望如此)时,下一步就是要使其更快]]。从可伸缩性的角度来看,应每个用户的请求向Servlet读取文件听起来并不合理。因此,我想到的是在上下文初始化期间仅将文件的内容读入ArrayList
(或其他集合)一次,然后将该ArrayList(而不是文件)作为上下文范围的数据持有者属性来共享。然后,可以使用与上述相同的锁定机制由servlet共享上下文范围的属性,并且可以在某些常规基础上将更新后的ArrayList的内容独立存储回文件中。
[另一种解决方案(为了避免锁定)将使用CopyOnWriteArrayList
(或java.util.concurrent
程序包中的其他集合)来保存共享数据,并指定单线程ExecutorService
将其内容转储到文件中需要的时候。我也听说过Java内存映射文件将整个文件映射到内部存储器,但是不确定这种方法是否适合这种特殊情况。
因此,任何人都可以指导我彻底解决最有效的方法(也许是建议其他替代方法),以解决共享文件访问的问题,但前提是写入文件的频率非常低并且其内容是预计不会超过数十行。
我正在开发一个小型Web应用程序,其Servlet定期访问共享资源,该资源是服务器端包含一些可变数据行的简单文本文件。大多数情况下,servlts ...
您不解释自己的真正问题,仅是您当前的尝试,很难提供一个好的解决方案。