Trong ArrayBlockingQueue, tại sao lại sao chép trường thành viên cuối cùng vào biến cuối cùng cục bộ?


81

Trong ArrayBlockingQueue, tất cả các phương thức yêu cầu khóa sao chép nó vào một finalbiến cục bộ trước khi gọi lock().

public boolean offer(E e) {
    if (e == null) throw new NullPointerException();
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        if (count == items.length)
            return false;
        else {
            insert(e);
            return true;
        }
    } finally {
        lock.unlock();
    }
}

Có lý do gì để sao chép this.lockvào biến cục bộ lockkhi trường this.locknày finalkhông?

Ngoài ra, nó cũng sử dụng bản sao cục bộ của E[]trước khi hành động trên đó:

private E extract() {
    final E[] items = this.items;
    E x = items[takeIndex];
    items[takeIndex] = null;
    takeIndex = inc(takeIndex);
    --count;
    notFull.signal();
    return x;
}

Có lý do gì để sao chép một trường cuối cùng vào một biến cuối cùng cục bộ không?

Câu trả lời:


68

Đó là một tối ưu hóa cực độ Doug Lea, tác giả của lớp học, thích sử dụng. Đây là một bài đăng trên một chủ đề gần đây trên danh sách gửi thư core-libs-dev về chủ đề chính xác này trả lời câu hỏi của bạn khá tốt.

từ bài đăng:

... sao chép cho người dân địa phương tạo ra mã bytecode nhỏ nhất và đối với mã cấp thấp, thật tuyệt khi viết mã gần với máy hơn một chút


15
Nhấn mạnh vào "cực"! Đây không phải là một phương pháp lập trình tốt cho mục đích chung mà mọi người nên học theo.
Kevin Bourrillion

15
FYI ngẫu nhiên: trong một số trường hợp khác khi bạn thấy điều này được thực hiện, đó là do trường được đề cập là không ổn định và phương pháp cần đảm bảo rằng nó có một giá trị nhất quán hoặc tham chiếu cho nó xuyên suốt.
Kevin Bourrillion

2
Tôi sẽ thực hiện tối ưu hóa "cực độ" này trong một lớp cốt lõi như thế này.
Erick Robertson,

4
@zamza, biến thức địa phương chỉ được sử dụng bởi trình biên dịch java, không phải là bytecode (tức là JVM không biết nếu một biến địa phương là cuối cùng)
bestsss

1
Ngoài kích thước bytecode, đây có phải là một tối ưu hóa cho tốc độ thực thi không?
SantiBailors

13

Chủ đề này đưa ra một số câu trả lời. Về chất:

  • trình biên dịch không thể dễ dàng chứng minh rằng trường cuối cùng không thay đổi trong một phương thức (do phản chiếu / tuần tự hóa, v.v.)
  • hầu hết các trình biên dịch hiện tại thực sự không thử và do đó sẽ phải tải lại trường cuối cùng mỗi khi nó được sử dụng, điều này có thể dẫn đến lỗi bộ nhớ cache hoặc lỗi trang
  • lưu trữ nó trong một biến cục bộ buộc JVM chỉ thực hiện một tải

2
Tôi không nghĩ rằng một finalbiến phải được tải lại bởi JVM. Nếu bạn sửa đổi một finalbiến thông qua phản chiếu, bạn sẽ mất đảm bảo chương trình của mình hoạt động chính xác (có nghĩa là giá trị mới có thể không được tính đến trong mọi trường hợp).
icza
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.