มีความแตกต่างระหว่างการvolatileอ้างอิงวัตถุหรือไม่AtomicReferenceในกรณีที่ฉันจะใช้get()และ - set()วิธีการจากAtomicReference?
มีความแตกต่างระหว่างการvolatileอ้างอิงวัตถุหรือไม่AtomicReferenceในกรณีที่ฉันจะใช้get()และ - set()วิธีการจากAtomicReference?
คำตอบ:
คำตอบสั้น ๆ คือไม่
จากjava.util.concurrent.atomicเอกสารกำกับแพคเกจ อ้างถึง:
เอฟเฟกต์หน่วยความจำสำหรับการเข้าถึงและการอัพเดตอะตอมโดยทั่วไปจะเป็นไปตามกฎสำหรับสารระเหย:
getมีผลต่อหน่วยความจำของการอ่านvolatileตัวแปรsetมีเอฟเฟกต์หน่วยความจำของการเขียน (กำหนด)volatileตัวแปร
อย่างไรก็ตามเอกสารนั้นดีมากและมีการอธิบายทุกอย่าง
AtomicReference::lazySetเป็นการดำเนินการที่ใหม่กว่า (Java 6+) ที่นำมาใช้ซึ่งมีความหมายที่ไม่สามารถเข้าใจได้ผ่านvolatileตัวแปร ดูโพสต์นี้สำหรับข้อมูลเพิ่มเติม
ไม่มีไม่มี
พลังเพิ่มเติมที่ให้มาโดย AtomicReference คือเมธอด CompareAndSet () และเพื่อน ๆ หากคุณไม่ต้องการวิธีการเหล่านั้นการอ้างอิงแบบระเหยจะให้ความหมายเช่นเดียวกับ AtomicReference.set () และ. get ()
มีความแตกต่างและการแลกเปลี่ยนหลายประการ:
ใช้AtomicReferenceรับ / ชุดมีเหมือนกันความหมาย JMMเป็นฟิลด์ระเหย (เป็นรัฐ Javadoc), การ แต่AtomicReferenceเป็นเสื้อคลุมรอบการอ้างอิงเพื่อการเข้าถึงใด ๆ ไปยังเขตข้อมูลที่เกี่ยวข้องกับการไล่ล่าตัวชี้ต่อไป
รอยความทรงจำคูณ (สมมติให้มีการบีบอัดสภาพแวดล้อม OOPS ที่เป็นจริงให้มากที่สุด VMs):
AtomicReference = 4b + 16b (ส่วนหัวของวัตถุ 12b + ฟิลด์อ้างอิง 4b)AtomicReferenceมี API ที่สมบูรณ์กว่าการอ้างอิงที่เปลี่ยนแปลงได้ คุณสามารถฟื้น API สำหรับการอ้างอิงระเหยโดยใช้AtomicFieldUpdaterหรือกับ Java VarHandle9 คุณยังสามารถเข้าถึงตัวตรงได้sun.misc.Unsafeหากคุณชอบวิ่งด้วยกรรไกร AtomicReferenceดำเนินการเองโดยใช้Unsafeไฟล์.
ดังนั้นเมื่อใดจึงควรเลือกอย่างใดอย่างหนึ่ง:
AtomicReference/ AtomicFieldUpdater/ Unsafeที่คุณมักจะจ่ายเงินด้วยความสามารถในการอ่านและความเสี่ยงที่จะได้รับ AtomicReferenceถ้าเรื่องนี้ไม่ได้เป็นเพียงแค่พื้นที่อ่อนไหวไป โดยทั่วไปผู้เขียนไลบรารีจะใช้วิธีการเหล่านี้ผสมผสานกันขึ้นอยู่กับ JDK ที่เป็นเป้าหมายข้อ จำกัด ของ API ที่คาดไว้ข้อ จำกัด ของหน่วยความจำและอื่น ๆซอร์สโค้ด JDKเป็นหนึ่งในวิธีที่ดีที่สุดในการตอบความสับสนเช่นนี้ หากคุณดูโค้ดใน AtomicReference จะใช้ตัวแปร volatie สำหรับการจัดเก็บอ็อบเจ็กต์
private volatile V value;
เห็นได้ชัดว่าถ้าคุณจะใช้ get () และ set () ใน AtomicReference มันก็เหมือนกับการใช้ตัวแปรระเหย แต่ตามที่ผู้อ่านคนอื่น ๆ แสดงความคิดเห็น AtomicReference ให้ความหมาย CAS เพิ่มเติม ดังนั้นก่อนอื่นให้ตัดสินใจว่าคุณต้องการความหมายของ CAS หรือไม่และถ้าคุณทำเพียงอย่างเดียวแล้วใช้ AtomicReference
AtomicReferenceมีฟังก์ชันเพิ่มเติมที่ไม่มีตัวแปรระเหยธรรมดา ดังที่คุณได้อ่าน API Javadoc คุณจะรู้สิ่งนี้ แต่ยังมีการล็อคที่มีประโยชน์สำหรับการดำเนินการบางอย่าง
อย่างไรก็ตามหากคุณไม่ต้องการฟังก์ชันเพิ่มเติมนี้ฉันขอแนะนำให้คุณใช้volatileฟิลด์ธรรมดา
volatileฟิลด์สามารถใช้งานได้เหมือนกับฟิลด์ทั่วไปในขณะที่การเข้าถึงค่าโดยAtomicReferenceต้องผ่านgetและsetวิธีการ
บางครั้งแม้ว่าคุณจะใช้แค่ gets และ set แต่ AtomicReference อาจเป็นทางเลือกที่ดี:
ตัวอย่างที่มีความผันผวน:
private volatile Status status;
...
public setNewStatus(Status newStatus){
status = newStatus;
}
public void doSomethingConditionally() {
if(status.isOk()){
System.out.println("Status is ok: " + status); // here status might not be OK anymore because in the meantime some called setNewStatus(). setNewStatus should be synchronized
}
}
การใช้งานกับ AtomicReference จะทำให้คุณมีการซิงโครไนซ์แบบ copy-on-write ฟรี
private AtomicReference<Status> statusWrapper;
...
public void doSomethingConditionally() {
Status status = statusWrapper.get();
if(status.isOk()){
System.out.println("Status is ok: " + status); // here even if in the meantime some called setNewStatus() we're still referring to the old one
}
}
อาจมีคนบอกว่าคุณยังสามารถมีสำเนาที่เหมาะสมได้หากคุณเปลี่ยนตัว:
Status status = statusWrapper.get();
กับ:
Status statusCopy = status;
อย่างไรก็ตามอันที่สองมีแนวโน้มที่จะถูกใครบางคนลบออกโดยไม่ได้ตั้งใจในอนาคตระหว่าง "การล้างโค้ด"