Java 并发读/写

标签 java concurrency client-server synchronized

我正在用 Java 制作一个客户端服务器应用程序。简而言之,服务器有一些文件。客户端可以向服务器发送文件,客户端可以请求从服务器下载所有文件。我使用 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 方法同步

我想知道这是否会造成一些麻烦。当客户端A正在添加一个文件而客户端B同时请求所有文件时,或者反之亦然,这会造成麻烦吗?或者 addFile 方法会因为同步而等待(或让其他方法等待)吗?

提前致谢!

最佳答案

是的,这可能会引起麻烦。其他线程可以访问 requestFiles(),而单个线程正在执行 addFile() 方法。

It is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

[来源] http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

因此,声明为同步的方法将实例锁定到该实例中的所有同步方法(在您的情况下是 Server 的实例)。如果您也同步了 requestFiles() 方法,那么您实际上将完全同步对服务器实例的访问。所以你不会有这个问题。

您还可以在文件映射上使用同步块(synchronized block)。请参阅这个 stackoverflow 问题: Java synchronized block vs. Collections.synchronizedMap

<小时/>

话虽如此,每当写入或读取文件时本质上锁定整个服务器对象的模型会阻碍并发设计。

根据您的设计的其余部分,并假设您使用“addFile()”方法编写的每个文件都有不同的名称,并且您不会覆盖文件。我会探索如下内容:

完全删除映射,并让每个方法分别与文件系统交互。

我会对“addFile()”写入的文件使用临时 (.tmp) 扩展名,然后(一旦写入文件)执行原子文件重命名,将扩展名转换为“.txt”文件。

Files.move(src, dst, StandardCopyOption.ATOMIC_MOVE);

然后将整个“requestFiles()”方法限制为仅“.txt”文件。这样文件写入和文件读取可以并行发生。

显然使用您需要的任何扩展。

关于Java 并发读/写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23310463/

相关文章:

java - lombok @Data 和 @Getter 不提供 getter 函数

java - JTable行删除错误

asp.net-mvc - 我应该使用相同的数据传输对象从服务器到客户端并返回

c - 如何计算套接字中的时间

Java 可选 Null Json 字段

java - 如何限制 akka actor 一次只做一项工作

concurrency - 如何使已编写的并发程序在GPU阵列上运行?

c++ - 为什么我的缓冲区在多次 read() 之后保存相同的数据?

java - 如何使用 javafx 或其他库有效地绘制许多数据点?

go - 如何从多个 goroutine 写入同一个 channel