简体   繁体   English

具有读写的Java并发

[英]Java concurrency with read/write

I'm making a client server application in Java. 我正在用Java开发客户端服务器应用程序。 In short, the Server has some files. 简而言之,服务器中有一些文件。 The Client can send a file to the Server and the Client can request to download all the files from the Server. 客户端可以将文件发送到服务器,客户端可以请求从服务器下载所有文件。 I'm using RMI for the Server and Client to communicate and I'm using the RMI IO library to send files between Client and Server. 我正在使用RMI进行服务器和客户端之间的通信,并且正在使用RMI IO库在客户端和服务器之间发送文件。

Some example code: 一些示例代码:

Server: 服务器:

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());
    }
}

Please note that this is just some example code to demonstrate. 请注意,这只是一些示例代码来演示。

My questions concerns concurrent access to the files on the Server. 我的问题与并发访问服务器上的文件有关。 As you can see, I've made the addFile method synchronized because it modifies the resources on my Server. 如您所见,我使addFile方法synchronized因为它修改了服务器上的资源。 My requestFiles method is not synchronized . 我的requestFiles方法 synchronized

I am wondering if this can cause some trouble. 我想知道这是否会造成一些麻烦。 When Client A is adding a File and Client B is at the same time requesting all files, or vice versa, will this cause trouble? 当客户端A添加文件而客户端B同时请求所有文件时,反之亦然,这会带来麻烦吗? Or will the addFile method wait (or make the other method wait) because it is synchronized ? 还是将addFile方法等待(或让另一个方法等待),因为它已synchronized

Thanks in advance! 提前致谢!

Yes this could cause trouble. 是的,这可能会引起麻烦。 Other threads could access requestFiles(), whilst a single thread is performing the addFile() method. 其他线程可以访问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. 当一个线程正在执行对象的同步方法时,所有其他调用同一对象块的同步方法的线程(挂起执行),直到第一个线程对该对象完成。

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

So methods that are declared syncronised lock the instance to all syncronised methods in that instance (In your case the instance of Server). 因此,被声明为同步化的方法会将实例锁定到该实例中的所有同步化方法(在您的情况下为Server实例)。 If you had the requestFiles() method syncronised as well, you would essentially be syncronising access to the Server instance completely. 如果您还同时同步了requestFiles()方法,则实际上将完全同步对Server实例的访问。 So you wouldn't have this problem. 这样您就不会有这个问题。

You could also use syncronised blocks on the files map. 您也可以在文件映射上使用同步块。 See this stackoverflow question: Java synchronized block vs. Collections.synchronizedMap 看到这个stackoverflow问题: Java同步块与Collections.synchronizedMap


That being said, a model that essentially locks the entire Server object whenever a file is being written or read is hampering a concurrent design. 话虽这么说,无论何时写入或读取文件,实质上锁定整个Server对象的模型都妨碍了并行设计。

Depending on the rest of your design and assuming each file you write with the 'addFile()' method has a different name, and you are not overwriting files. 根据设计的其余部分,并假定使用'addFile()'方法编写的每个文件都具有不同的名称,并且您不会覆盖文件。 I would explore something like the following: 我将探索以下内容:

Remove the map completely, and have each method interact with the file system separately. 完全删除映射,并使每种方法分别与文件系统交互。

I would use a temporary (.tmp) extension for files being written by 'addFile()', and then (once the file has been written) perform an atomic file rename to convert the extension to a '.txt' file. 我将对由“ addFile()”写入的文件使用临时(.tmp)扩展名,然后(一旦写入文件)执行原子文件重命名,以将扩展名转换为“ .txt”文件。

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

Then restrict the entire 'requestFiles()' method to just '.txt' files. 然后将整个“ requestFiles()”方法限制为仅“ .txt”文件。 This way file writes and file reads could happen in parallel. 这样,文件写入和文件读取可以并行发生。

Obviously use whatever extensions you require. 显然使用您需要的任何扩展名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM