2010-05-09 35 views
7

ví dụ cổ điển của một máy chủ đơn giản:Hiệu quả của việc khai báo biến cuối cùng trong các phương thức là gì?

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(); 
     } 
    } 
} 

Tại sao nên Socket được khai báo là final? Có phải vì mới Thread xử lý yêu cầu có thể tham chiếu trở lại biến số socket trong phương pháp và gây ra một số loại ConcurrentModificationException?

Trả lời

13

Trong trường hợp này, biến phải là giá trị cuối cùng được sử dụng bên trong trường hợp ẩn danh Runnable.

Điều này là do đối tượng đó sẽ tồn tại khi biến đã biến mất phạm vi và do đó biến mất. Đối tượng nhận được một bản sao của biến. Để ẩn điều này, biến phải là cuối cùng để không ai có thể mong đợi các thay đổi trong một bản sao hiển thị cho một bản sao khác.

+0

Cảm ơn rất nhiều. – Finbarr

2

Bạn cần khai báo nó cuối cùng, không chỉ nên. Nếu không có điều đó, trình biên dịch không thể sử dụng nó trong việc thực thi lớp Runnable ẩn danh.

0

Biến cục bộ không được chia sẻ giữa các chuỗi. (Biến cục bộ là một phần của bản ghi kích hoạt và mỗi luồng có bản ghi kích hoạt riêng).

connection là biến cục bộ nên không thể chia sẻ giữa các chuỗi. Kể từ khi nó không được chia sẻ giữa các chủ đề, bạn cần phải làm cho nó final, do đó, nó không quan trọng đó là một biến địa phương (nó có thể được nhìn thấy giống như một giá trị không đổi).

0

Nó không có ý định giải quyết ConcurrentModificationException. Bất kỳ biến cục bộ nào được sử dụng bên trong một lớp-lồng nhau-lớp (chẳng hạn như một lớp bên trong vô danh) phải được khai báo là cuối cùng. Xem một cuộc thảo luận tương tự so với tuần cuối cùng ở đây:

method local innerclasses accessing the local variables of the method

Trên thực tế trong trường hợp bài có một đóng góp nhỏ vào đây để an toàn thread; sẽ không có vấn đề về khả năng hiển thị trên biến cuối cùng giữa các luồng. Tuy nhiên, điều này không đảm bảo an toàn luồng.

3

Hãy xem xét ví dụ sau:

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

Nếu c là không cuối cùng, khi bạn đạt đến b.goo(), nó sẽ trỏ đến rác, vì đó c sẽ thu gom rác - Một biến địa phương sau khi kết thúc một cuộc gọi phương thức.

+0

Bạn có ngụ ý rằng các biến cuối cùng không bị thu gom rác? Điều đó là sai. – Pindatjuh

+0

Vấn đề là KHÔNG thu gom rác thải. Lớp bên trong có tham chiếu mạnh mẽ đến biến đó. Các nhà thiết kế ngôn ngữ có thể cho phép sử dụng các biến cục bộ không phải cuối cùng bên trong các lớp bên trong. Tuy nhiên, điều này có thể gây nhầm lẫn cho nhà phát triển (xem phản hồi của Michaels), vì sẽ không rõ liệu các bài tập tham chiếu có được lớp bên trong nhìn thấy hay không. –

+0

@Pindatjuh - Tôi ngụ ý rằng các biến cuối cùng không bị thu gom rác * khi phương thức kết thúc *. @Eyal - Bạn nói đúng, ngôn ngữ có thể được thiết kế tốt hơn, vv Tuy nhiên, thiết kế hiện tại là những gì chúng tôi có ... –

2

tuyên bố biến phương thức cuối cùng có nghĩa là giá trị của nó không thể thay đổi; rằng nó chỉ có thể được thiết lập một lần. cách áp dụng trong ngữ cảnh này?

tôi đã biết về hạn chế này với các lớp ẩn danh trong một thời gian, nhưng tôi chưa bao giờ hiểu được lý do tại sao. tôi thấy rằng không ai khác thực sự hoặc là từ các phản ứng cho đến nay. một số googling bật lên dưới đây mà tôi nghĩ rằng một công việc tốt để giải thích nó.

Một lớp địa phương nặc danh có thể sử dụng biến địa phương vì trình biên dịch tự động cung cấp cho các lớp một instance field tin để giữ một bản sao của mỗi biến cục bộ lớp sử dụng. Trình biên dịch cũng thêm các tham số ẩn vào mỗi hàm tạo để khởi tạo các trường riêng tư được tạo tự động . Do đó, một lớp địa phương không thực sự truy cập vào các biến số địa phương , nhưng chỉ riêng các biến số riêng của chúng. Cách duy nhất này có thể hoạt động chính xác là nếu các biến số địa phương được khai báo cuối cùng, để chúng được đảm bảo không thay đổi. Với bảo đảm này tại chỗ, lớp học địa phương được đảm bảo rằng các bản sao nội bộ của các biến phản ánh chính xác các biến số địa phương thực tế .

tín dụng cho: http://renaud.waldura.com/doc/java/final-keyword.shtml#vars

chắc chắn không phải rõ ràng và một cái gì đó mà tôi nghĩ rằng trình biên dịch thực sự nên được ẩn từ các nhà phát triển.

+0

Câu trả lời hay, kỹ thuật bit. Tôi muốn thêm ** tại sao ** nó cần đảm bảo đó: bởi vì lớp bên trong có thể được GC và nếu biến cục bộ thay đổi sau đó và thay đổi cần được phản ánh cho cá thể lớp bên trong, được GC: một vấn đề tránh nếu biến là cuối cùng. – Pindatjuh

+0

'tuyên bố biến phương thức cuối cùng có nghĩa là giá trị của nó không thể thay đổi; rằng nó chỉ có thể được thiết lập một lần'. Không hẳn. Nó có nghĩa là ** tham chiếu đến đối tượng không thể thay đổi được. Giá trị vẫn có thể được thay đổi nhiều lần. (Trừ khi đối tượng là nguyên thủy) – mercury0114

Các vấn đề liên quan