มีความแตกต่างระหว่างการ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 VarHandle
9 คุณยังสามารถเข้าถึงตัวตรงได้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;
อย่างไรก็ตามอันที่สองมีแนวโน้มที่จะถูกใครบางคนลบออกโดยไม่ได้ตั้งใจในอนาคตระหว่าง "การล้างโค้ด"