2017-04-25 61 views
0

我設計了一個服務器 - 客戶端應用程序使用Java,我已經連接到服務器的一個以上的用戶。 服務器提供了一些功能,如:如何實現同步多線程中的Java應用程序

  • 下載文件
  • 創建文件
  • 書面方式/附加文件等

我發現需要同步的一些問題當兩個或更多的用戶發送相同的請求時。

例如:當用戶想下載同一個文件的同時,如何同步使用synchronized塊或任何其他方法這個動作?

//main (connecting 2 users in the server) 
ServerSocket server= new ServerSocket(8080, 50); 
MyThread client1=new MyThread(server); 
MyThread client2=new MyThread(server); 
client1.start(); 
client2.start(); 

這裏是我想同步方法:

//outstream = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));//output to client 
//instream = new BufferedReader(new InputStreamReader(sock.getInputStream()));//input from client 

public void downloadFile(File file,String name) throws FileNotFoundException, IOException { 
    synchronized(this) 
    { 

    if (file.exists()) { 
     BufferedReader readfile = new BufferedReader(new FileReader(name + ".txt")); 


     String newpath = "../Socket/" + name + ".txt"; 

     BufferedWriter socketfile = new BufferedWriter(new FileWriter(newpath)); 
     String line; 

     while ((line = readfile.readLine()) != null) { 
      outstream.write(line + "\n"); 
      outstream.flush(); 
      socketfile.write(line); 

     } 
     outstream.write("EOF\n"); 
     outstream.flush(); 
     socketfile.close(); 
     outstream.write("Downloaded\n"); 
     outstream.flush(); 
    } else { 
     outstream.write("FAIL\n"); 
    } 
    outstream.flush(); 

    } 
} 

注意:此方法是在擴展Thread,當我想正在使用的一類到「下載」文件中的覆蓋方法run()的


請問這個例子向我保證,當用戶想下載同一個文件其中一人將不得不等待?另一個會得到它嗎?謝謝你的時間!

+0

也許你會在這裏找到答案:[什麼'同步'是什麼意思?](http://stackoverflow.com/questions/1085709/what-does-synchronized-mean) – Sergey

+0

我閱讀它,我理解它,但我不知道如何在我的例子中 – Phill

回答

0

在併發鎖定被用來提供互斥一些一段代碼。對於鎖定,您可以像使用ReentrantLock和其他非結構化鎖一樣使用同步。

任何鎖定的主要目標是提供相互排斥的內部代碼片段,這意味着該片段一次只能由一個thead執行。鎖內部分稱爲臨界部分。

爲了達到一個適當的鎖定是不夠的只是將關鍵的代碼存在。此外,您必須確保在關鍵部分內對變量進行的修改僅在此處進行。因爲如果你鎖定了一段代碼,但是對裏面的變量的引用也被傳遞給了某個沒有任何鎖定的併發執行線程,那麼在這種情況下,鎖將不會保存你,你將得到一個數據競賽。鎖只保護關鍵部分的執行,只保證放置在關鍵部分的代碼一次只能由一個線程執行。

// outstream =新的BufferedWriter(新 OutputStreamWriter(sock.getOutputStream())); //輸出到客戶端 //插播=新的BufferedReader(新的InputStreamReader (襪子。的getInputStream())); //從客戶

公共無效downloadFile(文件文件,字符串名稱)輸入拋出 FileNotFoundException異常,IOException的{ 同步(本) {

誰是本所有者方法?客戶?如果是,那麼它將不起作用。你應該鎖定在同一個對象上。它應該與所有需要鎖定的線程共享。但在你的情況下,每個客戶端都會擁有自己的鎖,其他線程對其他線程的鎖一無所知。您可以在Client.class上鎖定。這將工作。

synchronize(this) vs synchronize(MyClass.class)

這樣做,你將有適當的鎖定讀取(下載)文件之後。但是寫什麼呢?想象一下在閱讀某些其他線程期間想要修改該文件的情況。但你只鎖定閱讀。您正在讀取文件的開頭,另一個線程正在修改它的結尾。因此,寫入線程將會成功,您將從邏輯上獲得損壞的文件,其中包含一個文件和另一個文件的結尾。當然,文件系統和標準java庫會試圖關注這些情況(通過在讀者\寫入中使用鎖定,鎖定文件偏移量等),但總的來說,這是一種可能的情況。所以你在寫入時也需要同樣的鎖定。讀寫方法應共享並使用相同的鎖。

當我們有正確的行爲但表現不佳時,我們已經到了一種情況。這是我們的權衡。但我們可以做得更好。現在我們對每個寫入和讀取方法使用相同的鎖,這意味着我們一次只能讀取或寫入一個任何文件。但這是不正確的,因爲我們可以修改或讀取不同的文件而不會有任何可能的損壞。所以更好的方法是將鎖與文件關聯,而不是整個方法。在這裏,尼奧來幫助你。

How can I lock a file using java (if possible)

https://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileLock.html

而實際上,你可以讀取一個文件同時如果偏移量是不同的。由於明顯的物理原因,您無法同時讀取文件的同一部分。但同時閱讀和關心補償似乎是一個巨大的開銷fmpv,我不知道你會需要。無論如何這裏是一些信息:Concurrent reading of a File (java preffered)