我正在用Java创建一个客户端服务器应用程序。简而言之,Server有一些文件。客户端可以将文件发送到服务器,客户端可以请求从服务器下载所有文件。我正在使用RMI进行服务器和客户端通信,我正在使用RMI IO库在客户端和服务器之间发送文件。
一些示例代码:
服务器
class Server implements ServerService {
// private Map<String, File> files;
private ConcurrentHashMap<String, File> files // Solution
// adding a file to the server
public synchronized void addFile(RemoteInputStream inFile, String filename)
throws RemoteException, IOException {
// From RMI IO library
InputStream istream = RemoteInputStreamClient.wrap(inFile);
File f = new File(dir, filename);
FileOutputStream ostream = new FileOutputStream(f);
while (istream.available() > 0) {
ostream.write(istream.read());
}
istream.close();
ostream.close();
files.put(filename, f);
}
// requesting all files
public requestFiles(ClientService stub)
throws RemoteException, IOException {
for(File f: files.values()) {
//Open a stream to this file and give it to the Client
RemoteInputStreamServer istream = null;
istream = new SimpleRemoteInputStream(new BufferedInputStream(
new FileInputStream(f)));
stub.receiveFile(istream.export());
}
}
请注意,这只是一些示例代码。
我的问题涉及对服务器上文件的并发访问。如您所见,我已经创建了addFile
方法synchronized
,因为它修改了我的服务器上的资源。我的requestFiles
方法不 synchronized
。
我想知道这是否会造成一些麻烦。当客户端A添加文件并且客户端B同时请求所有文件时,反之亦然,这会导致问题吗?或者addFile
方法会等待(或让其他方法等待),因为它是synchronized
?
提前致谢!
答案 0 :(得分:1)
是的,这可能会造成麻烦。其他线程可以访问requestFiles(),而单个线程正在执行addFile()方法。
两次调用同步方法是不可能的 在同一个对象上进行交错。当一个线程正在执行时 对象的synchronized方法,所有其他调用的线程 同一对象块的同步方法(暂停执行) 直到第一个线程完成对象。
[来源] http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
因此声明同步的方法会将实例锁定到该实例中的所有同步方法(在您的情况下是Server的实例)。如果您同时使用requestFiles()方法同步,那么您实际上将完全同步对Server实例的访问。所以你不会有这个问题。
您还可以在文件地图上使用同步块。请参阅此stackoverflow问题: Java synchronized block vs. Collections.synchronizedMap
话虽这么说,每当写入或读取文件时,基本上锁定整个Server对象的模型都会妨碍并发设计。
根据您的设计的其余部分,并假设您使用'addFile()'方法编写的每个文件具有不同的名称,并且您不会覆盖文件。我会探索以下内容:
完全删除地图,让每个方法分别与文件系统交互。
我会对'addFile()'编写的文件使用临时(.tmp)扩展名,然后(一旦写完文件)执行原子文件重命名,将扩展名转换为'.txt'文件
Files.move(src, dst, StandardCopyOption.ATOMIC_MOVE);
然后将整个'requestFiles()'方法限制为'.txt'文件。这样,文件写入和文件读取可以并行发生。
显然使用您需要的任何扩展程序。