7

単純なサーバーの典型的な例:

class ThreadPerTaskSocketServer {
   public static void main(String[] args) throws IOException {
      ServerSocket socket = new ServerSocket(80);
      while (true) {
          final Socket connection = socket.accept();
          Runnable task = new Runnable() {
              public void run() {
                 handleRequest(connection);
              }
          };
          new Thread(task).start();
      }
   }
}

なぜSocketとして宣言する必要がありますfinalか?Threadリクエストを処理するnewがsocketメソッド内の変数を参照し直して、ある種の原因となる可能性があるためConcurrentModificationExceptionですか?

4

6 に答える 6

13

この場合、匿名の実装内で使用するには、変数がfinalである必要がありますRunnable

これは、変数がすでにスコープから外れて消えたときにそのオブジェクトが存在するためです。オブジェクトは変数のコピーを取得します。これを非表示にするには、変数がfinalである必要があります。これにより、一方のコピーの変更がもう一方のコピーに表示されることを誰も期待できなくなります。

于 2010-05-09T19:44:42.697 に答える
3

この例を考えてみましょう。

class A {
  B foo() {
    final C c;
    return new B() {
      void goo() {
        // do something with c
      }
    }
  }
}
// somewhere else in the code
A a = new A();
B b = a.foo();
b.goo();

cがfinalでない場合、に到達するb.goo()と、そのcはガベージコレクションされるため、ジャンクを指します-メソッド呼び出しの終了後のローカル変数。

于 2010-05-09T19:54:10.080 に答える
2

あなたはそれを最終的に宣言する必要があります。これがないと、コンパイラは匿名のRunnableクラスの実装でそれを使用できません。

于 2010-05-09T19:43:20.040 に答える
2

メソッド変数finalを宣言することは、その値が変更できないことを意味します。一度しか設定できないこと。それはこの文脈でどのように適用されますか?

匿名クラスでのこの制限については以前から知っていましたが、その理由を完全には理解していませんでした。これまでのところ、他の誰も実際にどちらの回答もしていません。いくつかのグーグルが下に現れました、それは私がそれを説明するのに良い仕事をしていると思います。

匿名ローカルクラスはローカル変数を使用できます。これは、コンパイラがクラスにプライベートインスタンスフィールドを自動的に与えて、クラスが使用する各ローカル変数のコピーを保持するためです。コンパイラーはまた、これらの自動的に作成されたプライベート・フィールドを初期化するために、各コンストラクターに隠しパラメーターを追加します。したがって、ローカルクラスは実際にはローカル変数にアクセスするのではなく、それらのプライベートコピーにアクセスするだけです。これが正しく機能する唯一の方法は、ローカル変数がfinalとして宣言されている場合です。これにより、ローカル変数が変更されないことが保証されます。この保証が適用されると、ローカルクラスは、変数の内部コピーが実際のローカル変数を正確に反映することが保証されます。

クレジット: http: //renaud.waldura.com/doc/java/final-keyword.shtml#vars

確かに明白ではなく、コンパイラが実際に開発者から隠すべきだと私は思います。

于 2010-05-09T20:46:21.260 に答える
0

ローカル変数はスレッド間で共有されません。(ローカル変数はアクティベーションレコードの一部であり、各スレッドには独自のアクティベーションレコードがあります)。

connectionはローカル変数であるため、スレッド間で共有することはできません。スレッド間で共有されないため、作成する必要がありますfinal。ローカル変数であるかどうかは関係ありません(定数値のように見えます)。

于 2010-05-09T19:43:26.573 に答える
0

ConcurrentModificationExceptionを解決することを目的としたものではありません。メソッドネストクラス(匿名内部クラスなど)内で使用されるローカル変数は、finalとして宣言する必要があります。ここで先週からの同様の議論を参照してください:

メソッドのローカル変数にアクセスするメソッドローカル内部クラス

実際、スレッドの場合、ここではスレッドの安全性にわずかな貢献があります。スレッド間の最終変数の可視性の問題はありません。ただし、これはスレッドの安全性をまったく保証するものではありません。

于 2010-05-09T19:47:46.980 に答える