2017-04-25 13 views
0

Javaを使用してサーバークライアントアプリケーションを設計しましたが、複数のユーザーに複数のサーバーに接続しています。私は同期する必要があるいくつかの問題を発見し マルチスレッドJavaアプリケーションの同期を実現する方法


  • ファイルのダウンロード
  • 作成ファイル
  • 足す/追加ファイルなど: サーバーは、次のようないくつかの機能を提供し、 2人以上のユーザーが同じ要求を送信したとき。

    例:ユーザーが同じファイルを同時にダウンロードしたい場合、どのように同期化されたブロックまたは他の方法を使用してこの操作を同期できますか?ここで

    //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()


    2人のユーザーが同じファイルをダウンロードしたい場合、そのうちの1人が待たなければならないことをこの例では保証していますか?他の人はそれを手に入れますか?御時間ありがとうございます!

+0

多分あなたはここに答えを見つけるでしょう:[同期は何を意味するのですか?](http://stackoverflow.com/questions/1085709/what-does-synchronized-mean) – Sergey

+0

私はそれを読んで私もそれを理解したが、私の例でそれを行う方法を知らない – Phill

答えて

0

同時ロックは、一部のコードに相互排除を提供するために使用されます。ロックの場合、ReentrantLockなどの非構造化ロックと同期して使用できます。

ロックの主な目的は、内部に配置されたコード部分に相互排除を提供することです。このコードは、一度に1つずつしか実行されません。ロック内のセクションをクリティカルセクションと呼びます。

適切なロックを実現するには、重要なコードを配置するだけでは十分ではありません。また、クリティカルセクション内で作成された変数の変更がそこでのみ行われるようにする必要があります。なぜなら、コードのいくつかをロックしていても、内部の変数への参照がロックなしで実行中のスレッドに渡されてしまったからです。その場合はロックしないとデータ競合が発生します。ロックはクリティカルセクションの実行のみを保護し、クリティカルセクションに配置されたコードは一度に1つのスレッドのみで実行されることを保証します。 //クライアント への出力が//インストリーム=新しいをBufferedReader(新しい にInputStreamReader(靴下; // OUTSTREAM =新しいBufferedWriterの(新しい のOutputStreamWriter(sock.getOutputStream()))

。getInputStream()));にFileNotFoundExceptionは、IOException { が同期 //クライアント

ます。public void downloadFile(ファイルのファイル、文字列名)からの入力がスローされます(この) これの所有者である{

方法?クライアント?はいの場合は動作しません。同じオブジェクトをロックする必要があります。ロックを必要とするすべてのスレッドと共有する必要があります。しかし、あなたの場合、すべてのクライアントはそれ自身のロックを持ち、他のスレッドは他のスレッドのロックについて何も知らないでしょう。 Client.classでロックすることができます。これは動作します。あなたは(ダウンロード)ファイルを読み込むための適切なロックを持っていることをやった後

synchronize(this) vs synchronize(MyClass.class)

。しかし、書き込みについてはどうですか?読んでいる間に、他のスレッドがそのファイルを変更したいと思う場合を想像してください。しかし、あなたは読書のためだけにロックを持っています。あなたはファイルの先頭を読んでおり、他のスレッドはファイルの終わりを修正しています。したがって、書き込みスレッドは成功し、1つのファイルからの呼び出しともう一方のファイルの最後で、論理的に破損したファイルが取得されます。もちろん、ファイルシステムと標準のJavaライブラリは、このような場合に注意を払うようにしようとします(読者の書き込みでロックを使用する、ファイルのオフセットをロックするなど)が、一般的に可能なシナリオです。したがって、同じ書き込みロックが必要になります。また、読み書きメソッドは同じロックを共有して使用する必要があります。

私たちは正しく動作しているものの、パフォーマンスが低い状況に遭遇しました。これは我々のトレードオフです。しかし、私たちはより良くすることができます。現在、すべての書き込みと読み取りの方法で同じロックを使用しています。これは、一度に1つのファイルだけを読み書きできることを意味します。しかし、これは正しいファイルではありません。なぜなら、改ざんされることなく、別のファイルを変更または読み取ることができるからです。したがって、より良いアプローチは、メソッド全体ではなくファイルにロックを関連付けることです。そしてここでニオはあなたを助けるために来ます。

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)

関連する問題