2012-07-11 5 views
9

変数int x = 1があり、メインスレッドで実行可能ファイルを宣言していて、実行可能ファイルのrun()メソッドにxを渡したい場合は、finalと宣言する必要があります。どうして?なぜrunnableに渡される変数が最終的に必要なのですか?

final int x = 0;//<----must be final... 
private class myRun implements Runnable { 

    @Override 
    public void run() { 
     x++;// 
    } 

} 
+1

これが言語の定義方法であるためです。おそらく、*匿名の内部クラス*内の上記のメソッド内で*変数*が変更されないようにする。 (私はそれも実装を簡素化すると信じています:*値*だけがプロキシを匿名型にコピーする必要があり、完全なクロージャのセマンティクスで必要とされるように元の変数を保持する必要はありません) –

+0

そうではありませんでしたが、あなたの変数は警告なしにいつでも変更される可能性があります。 – jahroy

答えて

8

彼らは変更されることが可能であるならば、それは多くの問題を引き起こす可能性があるため、これを考慮してください。

public void count() 
{ 
    int x; 

    new Thread(new Runnable() 
    { 
     public void run() 
     { 
      while(x < 100) 
      { 
       x++; 
       try 
       { 
        Thread.sleep(1000); 
       }catch(Exception e){} 
      } 
     } 
    }).start(); 

    // do some more code... 

    for(x = 0;x < 5;x++) 
     for(int y = 0;y < 10;y++) 
      System.out.println(myArrayElement[x][y]); 
} 

これはおおまかな例ですが、説明できないエラーが多く発生する可能性があります。これが変数が最終的でなければならない理由です。上記の問題に対する単純な修正があります:

public void count() 
{ 
    int x; 

    final int w = x; 

    new Thread(new Runnable() 
    { 
     public void run() 
     { 
      int z = w; 

      while(z < 100) 
      { 
       z++; 
       try 
       { 
        Thread.sleep(1000); 
       }catch(Exception e){} 
      } 
     } 
    }).start(); 

    // do some more code... 

    for(x = 0;x < 5;x++) 
     for(int y = 0;y < 10;y++) 
      System.out.println(myArrayElement[x][y]); 
} 

さらに詳しい説明が必要な場合は、同期のようなものです。 Javaでは、複数のスレッドから1つのオブジェクトを参照できないようにしたいと考えています。

ホープ、この助けた:ここでの同期について少しです!

+1

これは多くの問題を引き起こしません - 多くの言語は完全なクロージャを持っています:-) Runnable(とおそらくスレッド)がここのトピックにあるという事実匿名の内部型からローカル変数を変更できるようにすることとは正反対です。スレッディングを扱っていないことについて話しても、同じ言語規則になります。また、同じスレッドの問題はメンバ変数から発生します。 –

+1

"ここでは上記の問題に対する簡単な修正があります:"、w ++ではコンパイルエラーが発生しませんか?あなたはそれを初期化した後にwを再割り当てすることはできません。 – mskw

+0

@mskw誰も今まで何も言わなかったと信じられません。 – John

6

これは言語仕様の意味です。 According to Guy Steele、この選択肢の根底にある理論的根拠は、メソッド内でint x = 0という宣言がスタックに割り当てられた記憶域になると期待していますが、メソッドからnew myRun()を返すことができれば(そうでなければmyRunは関数の戻り値を超えています)後でそれを変更することができます。次に、xをヒープ割り当てして、期待するセマンティクスを持たなければなりません。

これは可能性がありますが、実際には他の言語でもそうしています。しかし、Java設計者は、代わりにxfinalとマークすることを要求し、実装がスタック割り当てストレージのように見えるようにヒープ割り当てを行わないようにすることを決めました。

(私は注意する必要があります。これはRunnableに固有ではありませんそれは匿名内部クラスに適用されます)

+0

ああ、そうです、私は質問を誤解しました。 – jacobm

+0

+1 "それはRunnableに固有のものではありません" –

1

マルチスレッド化の大きな問題とそれを使用する理由は、複数のことが同時に起こっていることです。突然、あなたのスレッドがアクセスする、スレッドにローカルではない変数の値はいつでも変更できます。したがって、あなたは、あなただけの数字、このコードで1-10のものに印刷している可能性があります

int x = 0; //supposing that this was allowed to be non-final... 
    private class myRun implements Runnable{ 

    @Override 
    public void run() { 
     for (int i=0; i<10; i++) { 
      System.Out.Println(x++); 
     } 
    } 
} 

をしかし、そのクラス内の他のコードは、xの値を変更した場合、現実には、あなたは230498印刷し終わる可能性 - 230508をx の値は、ループの途中でイベントが変化する可能性があります。特定の値を持つxに頼ることができない場合や、以前に割り当てた値を保持していない場合は、コードで使用するのは無駄になります。変数が帽子のドロップで変化する可能性がある場合は、なぜ変数を使用しますか?

Javaを使用することをまったく禁止するのではなく、Javaではfinalとする必要があります。他のスレッドからxの値を決して変更しないことを「約束する」ことができますが、まずそれをfinalにしてコンパイラを助けてください。確かに、xに割り当てられた初期値にしかアクセスできませんが、変数の初期値にアクセスできるだけでは、それをまったく使用できない場合よりも優れているため、残りのデータを利用するスレッドの能力を効果的に遮断しますあなたのクラスの。

関連する問題