Câu trả lời:
Khi nhiều chủ đề cần kiểm tra và thay đổi boolean. Ví dụ:
if (!initialized) {
initialize();
initialized = true;
}
Đây không phải là chủ đề an toàn. Bạn có thể sửa nó bằng cách sử dụng AtomicBoolean
:
if (atomicInitialized.compareAndSet(false, true)) {
initialize();
}
true
khi initialize()
chưa hoàn thành. Vì vậy, nó chỉ hoạt động nếu các chủ đề khác không quan tâm đến việc hoàn thành initialize()
.
initialized
chỉ đơn giản được sử dụng để đảm bảo rằng một và chỉ một luồng sẽ gọi initialize()
phương thức. Rõ ràng initialized
là đúng không có nghĩa là việc khởi tạo chắc chắn đã hoàn thành trong trường hợp này, vì vậy có lẽ một thuật ngữ hơi khác sẽ tốt hơn ở đây. Một lần nữa, nó phụ thuộc vào những gì nó được sử dụng cho.
volatile boolean
giống như AtomicBoolean
?
synchronized
khối, trong trường hợp đó bạn không còn cần AtomicBoolean
, chỉ cần a volatile boolean
. ( if(! this.initialized) { synchronized(this) { if(! this.initialized) { initialize(); this.initialized = true; } } }
sẽ đảm bảo rằng chỉ có một cuộc gọi luồng initialize
và tất cả các luồng khác chờ nó thực hiện, với điều kiện initialized
được đánh dấu volatile
.)
Dưới đây là những ghi chú (từ cuốn sách Brian Goetz ) tôi đã thực hiện, điều đó có thể giúp ích cho bạn
Các lớp nguyên tử
cung cấp triển khai So sánh và chặn không chặn
Tận dụng lợi thế của sự hỗ trợ được cung cấp bởi phần cứng (hướng dẫn CMPXCHG trên Intel) Khi có nhiều luồng đang chạy qua mã của bạn sử dụng API đồng thời nguyên tử này, chúng sẽ mở rộng tốt hơn nhiều so với mã sử dụng trình giám sát / đồng bộ hóa mức đối tượng. Do các cơ chế đồng bộ hóa của Java làm cho mã chờ, khi có rất nhiều luồng chạy qua các phần quan trọng của bạn, một lượng thời gian CPU đáng kể được dành để quản lý chính cơ chế đồng bộ hóa (chờ, thông báo, v.v.). Do API mới sử dụng các cấu trúc mức phần cứng (biến nguyên tử) và chờ và khóa các thuật toán miễn phí để thực hiện an toàn luồng, nên phần lớn thời gian của CPU được dành cho "làm công cụ" thay vì quản lý đồng bộ hóa.
không chỉ cung cấp thông lượng tốt hơn, mà chúng còn cung cấp sức đề kháng cao hơn đối với các vấn đề sinh động như bế tắc và đảo ngược ưu tiên.
Có hai lý do chính tại sao bạn có thể sử dụng boolean nguyên tử. Đầu tiên, nó có thể thay đổi, bạn có thể chuyển nó dưới dạng tham chiếu và thay đổi giá trị được liên kết với chính boolean chẳng hạn.
public final class MyThreadSafeClass{
private AtomicBoolean myBoolean = new AtomicBoolean(false);
private SomeThreadSafeObject someObject = new SomeThreadSafeObject();
public boolean doSomething(){
someObject.doSomeWork(myBoolean);
return myBoolean.get(); //will return true
}
}
và trong lớp someObject
public final class SomeThreadSafeObject{
public void doSomeWork(AtomicBoolean b){
b.set(true);
}
}
Quan trọng hơn, mặc dù, luồng của nó an toàn và có thể chỉ ra cho các nhà phát triển duy trì lớp, rằng biến này dự kiến sẽ được sửa đổi và đọc từ nhiều luồng. Nếu bạn không sử dụng AtomicBoolean, bạn phải đồng bộ hóa biến boolean bạn đang sử dụng bằng cách khai báo biến động hoặc đồng bộ hóa xung quanh việc đọc và ghi của trường.
Các AtomicBoolean
lớp học cung cấp cho bạn một giá trị boolean mà bạn có thể cập nhật nguyên tử. Sử dụng nó khi bạn có nhiều luồng truy cập vào một biến boolean.
Các tổng quan về gói java.util.concurrent.atomic mang đến cho bạn một mô tả cấp cao tốt về những gì các lớp trong gói này làm gì và khi nào thì sử dụng chúng. Tôi cũng muốn giới thiệu cuốn sách Đồng thời Java trong thực hành của Brian Goetz.
Trích từ mô tả gói
Gói java.util.concản.atomic Mô tả: Một bộ công cụ nhỏ gồm các lớp hỗ trợ lập trình an toàn luồng không khóa trên các biến đơn. [...]
Các thông số kỹ thuật của các phương pháp này cho phép triển khai sử dụng các hướng dẫn nguyên tử ở cấp độ máy hiệu quả có sẵn trên các bộ xử lý hiện đại. [...]
Các thể hiện của các lớp AtomicBoolean, AtomicInteger, AtomicLong và AtomicReference mỗi lớp cung cấp quyền truy cập và cập nhật cho một biến duy nhất của loại tương ứng. [...]
Các hiệu ứng bộ nhớ để truy cập và cập nhật các nguyên tử thường tuân theo các quy tắc cho các chất bay hơi:
- get có hiệu ứng bộ nhớ của việc đọc một biến dễ bay hơi.
- set có các hiệu ứng bộ nhớ của việc viết (gán) một biến dễ bay hơi.
- yếuCompareAndset đọc nguyên bản và ghi một cách có điều kiện một biến, được sắp xếp theo các hoạt động bộ nhớ khác trên biến đó, nhưng hoạt động như một hoạt động bộ nhớ không bay hơi thông thường.
- so sánh và tất cả các hoạt động đọc và cập nhật khác như getAndIncrement có hiệu ứng bộ nhớ của cả đọc và viết các biến dễ bay hơi.
volatile boolean
vsAtomicBoolean
: stackoverflow.com/questions/3786825/