2014-04-26 2 views
1

Java로 클라이언트 서버 응용 프로그램을 만들고 있습니다. 간단히 말해, 서버에는 몇 가지 파일이 있습니다. 클라이언트는 서버로 파일을 전송할 수 있으며 클라이언트는 서버에서 모든 파일을 다운로드하도록 요청할 수 있습니다. 서버와 클라이언트가 통신 할 수 있도록 RMI를 사용 중이며 RMI IO 라이브러리를 사용하여 클라이언트와 서버간에 파일을 보냅니다.Java 동시성 (읽기/쓰기)

일부 예제 코드 :

서버 :

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가 동시에 모든 파일을 요청하거나 그 반대 인 경우 문제가 발생합니까? 아니면 synchronized이기 때문에 addFile 메서드가 대기 할 것입니까 (다른 메서드가 대기 할 것입니까?)?

미리 감사드립니다.

답변

1

예. 문제가 발생할 수 있습니다. 단일 스레드가 addFile() 메소드를 수행하는 동안 다른 스레드는 requestFiles()에 액세스 할 수 있습니다.

같은 개체에 두 개의 동기화 된 메서드를 두 번 호출하면 인터리브 할 수 없습니다. 하나의 스레드가 객체에 대해 동기화 된 메소드를 실행하면 을 호출하는 다른 모든 스레드는 첫 번째 스레드가 객체로 완료 될 때까지 동일한 객체 블록 (실행 일시 중단) 에 대한 메소드를 동기화합니다.

은 [출처] http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

그래서 선언 syncronised하는 방법 (귀하의 경우에는 서버의 인스턴스)가 인스턴스의 모든 syncronised 방법으로 인스턴스를 잠급니다. requestFiles() 메서드도 동기화 된 경우 서버 인스턴스에 대한 액세스가 기본적으로 동기화됩니다. 그래서 당신은이 문제를 가지지 않을 것입니다.

파일 맵에서 동기화 된 블록을 사용할 수도 있습니다. 이 유래 질문을 참조 : 말했다되고 그건 Java synchronized block vs. Collections.synchronizedMap


, 기본적으로 파일이 작성하거나 읽을 때마다 전체 서버 개체를 잠그는 모델이 동시 설계를 방해한다.

디자인의 나머지 부분에 따라 'addFile()'메소드로 작성하는 각 파일이 다른 이름을 가지고 있으며 파일을 덮어 쓰지 않는다고 가정합니다. 다음과 같은 것을 탐색 할 것입니다 :

지도를 완전히 제거하고 각 방법을 파일 시스템과 별도로 조작하십시오.

임시 (.tmp) 확장자를 'addFile()'로 작성한 다음 (일단 파일을 작성하면) 원자 파일 이름 바꾸기를 수행하여 확장자를 '.txt'파일로 변환합니다.

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

그런 다음 전체 'requestFiles()'메소드를 '.txt'파일로 제한하십시오. 이 방법은 파일 쓰기와 파일 읽기가 동시에 일어날 수 있습니다.

분명히 필요한 확장명을 사용하십시오.

+0

디자인에서 파일을 덮어 쓸 수도 있습니다. 당신은 Map을 동기화하도록 만들 생각이십니까? (당신이 언급 한 stackoverflow 질문에서와 같이) – JNevens

+0

나는 ConcurrentHashMap을 사용할 것이고 put 작업은 원자 적이며 읽기 작업은 휘발성 변수를 읽는 것으로 동작합니다. ConcurrentHashMap 파일 = 새로운 ConcurrentHashMap (); – GoldenJam

+0

감사합니다. – JNevens