AtomicInteger lazySet กับ set


116

อะไรคือความแตกต่างระหว่างlazySetและsetวิธีการAtomicInteger? เอกสารไม่ได้มีมากที่จะพูดเกี่ยวกับlazySet:

ในที่สุดก็ตั้งค่าเป็นค่าที่กำหนด

ดูเหมือนว่าค่าที่จัดเก็บไว้จะไม่ถูกตั้งค่าเป็นค่าที่ต้องการในทันที แต่จะถูกกำหนดให้ตั้งเวลาในอนาคตแทน แต่การใช้วิธีนี้ในทางปฏิบัติคืออะไร? ตัวอย่างใด

คำตอบ:


114

อ้างจาก"JDK-6275329: เพิ่มเมธอด lazySet ให้กับคลาสอะตอม" :

เนื่องจากอาจเป็นการติดตามผล JSR166 เพียงเล็กน้อยสำหรับ Mustang เราจึงได้เพิ่มเมธอด "lazySet" ลงในคลาสอะตอม (AtomicInteger, AtomicReference ฯลฯ ) นี่เป็นวิธีการเฉพาะที่บางครั้งมีประโยชน์เมื่อปรับโค้ดโดยใช้โครงสร้างข้อมูลที่ไม่ปิดกั้น ความหมายคือการรับประกันว่าจะไม่มีการเรียงลำดับการเขียนซ้ำกับการเขียนก่อนหน้านี้ แต่อาจมีการเรียงลำดับใหม่ด้วยการดำเนินการที่ตามมา (หรือเทียบเท่ากับเธรดอื่น ๆ อาจมองไม่เห็น) จนกว่าจะมีการดำเนินการเขียนหรือซิงโครไนซ์อื่น ๆ เกิดขึ้น)

กรณีการใช้งานหลักคือการลบฟิลด์ของโหนดในโครงสร้างข้อมูลที่ไม่ปิดกั้นเพียงเพื่อหลีกเลี่ยงการกักเก็บขยะในระยะยาว จะใช้เมื่อไม่เป็นอันตรายหากเธรดอื่นเห็นค่าที่ไม่ใช่ค่าว่างชั่วขณะหนึ่ง แต่คุณต้องการให้แน่ใจว่าโครงสร้างเป็น GCable ในที่สุด ในกรณีเช่นนี้คุณจะได้รับประสิทธิภาพที่ดีขึ้นโดยหลีกเลี่ยงค่าใช้จ่ายในการเขียนค่าลบระเหย มีกรณีการใช้งานอื่น ๆ อีกสองสามกรณีตามบรรทัดเหล่านี้สำหรับอะตอมแบบไม่อ้างอิงเช่นกันดังนั้นวิธีนี้จึงได้รับการสนับสนุนในคลาส AtomicX ทั้งหมด

สำหรับคนที่ชอบคิดถึงการดำเนินการเหล่านี้ในแง่ของอุปสรรคระดับเครื่องบนตัวประมวลผลหลายตัวทั่วไป lazySet มีแผงกั้นร้านค้าก่อนหน้า (ซึ่งอาจเป็นแบบไม่ใช้งานหรือราคาถูกมากบนแพลตฟอร์มปัจจุบัน) แต่ไม่มีอุปสรรคในการจัดเก็บ (ซึ่งโดยปกติจะเป็นส่วนที่มีราคาแพงของการเขียนแบบระเหย)


14
ใครบางคนสามารถโง่ให้พวกเราที่เหลือได้ไหม? :(
Gaurav

14
Lazy เป็นเวอร์ชันที่ไม่ลบเลือน (เช่นไม่รับประกันว่าการเปลี่ยนสถานะจะมองเห็นได้ในทุกเธรดที่มีAtomic*ขอบเขต)
หาว

63
สิ่งที่ฉันไม่เข้าใจคือทำไม javadoc ถึงแย่กับมัน
Felipe

8
ฉันแน่ใจว่าในที่สุดพวกเขาก็จะเปลี่ยนมันได้ บูมบูม.
MMJZ

3
สำหรับผู้ที่ต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับแผงกั้นร้านค้า / ตู้บรรทุกและเหตุใดแผงกั้นร้านค้าจึงมีราคาถูกกว่าแผงกั้นสำหรับเก็บของ นี่คือบทความที่เข้าใจง่ายเกี่ยวกับเรื่องนี้ mechanical-sympathy.blogspot.com/2011/07/…
Kin Cheung

15

lazySet สามารถใช้สำหรับการสื่อสาร rmw inter thread เนื่องจาก xchg เป็นอะตอมสำหรับการมองเห็นเมื่อกระบวนการเธรดผู้เขียนแก้ไขตำแหน่งบรรทัดแคชโปรเซสเซอร์ของเธรดผู้อ่านจะเห็นในการอ่านครั้งถัดไปเนื่องจากโปรโตคอลการเชื่อมต่อแคชของซีพียู intel จะรับประกัน LazySet ใช้งานได้ แต่บรรทัดแคชจะได้รับการอัปเดตในการอ่านครั้งถัดไปอีกครั้งซีพียูจะต้องทันสมัยเพียงพอ

http://sc.tamu.edu/systems/eos/nehalem.pdf สำหรับ Nehalem ซึ่งเป็นแพลตฟอร์มแบบหลายโปรเซสเซอร์โปรเซสเซอร์จะมีความสามารถในการ "สอดแนม" (ดักฟัง) บัสแอดเดรสสำหรับการเข้าถึงหน่วยความจำระบบของโปรเซสเซอร์อื่นและ ไปยังแคชภายในของพวกเขา พวกเขาใช้ความสามารถในการสอดแนมนี้เพื่อให้แคชภายในสอดคล้องกันทั้งกับหน่วยความจำระบบและแคชในโปรเซสเซอร์อื่น ๆ ที่เชื่อมต่อกัน หากผ่านการสอดแนมโปรเซสเซอร์ตัวหนึ่งตรวจพบว่าโปรเซสเซอร์อื่นตั้งใจที่จะเขียนไปยังตำแหน่งหน่วยความจำที่ปัจจุบันได้แคชไว้ในสถานะ Shared หน่วยประมวลผลการสอดแนมจะทำให้บล็อกแคชเป็นโมฆะบังคับให้ดำเนินการกรอกบรรทัดแคชในครั้งต่อไปที่เข้าถึงตำแหน่งหน่วยความจำเดียวกัน .

oracle hotspot jdk สำหรับสถาปัตยกรรม x86 cpu ->

lazySet == unsafe.putOrderLong == xchg rw (คำสั่ง asm ที่ทำหน้าที่เป็น soft barrier ซึ่งคิดราคา 20 รอบบน nehelem intel cpu)

บน x86 (x86_64) อุปสรรคดังกล่าวมีประสิทธิภาพที่ถูกกว่ามากเมื่อเทียบกับการระเหยหรือ AtomicLong getAndAdd

ในผู้ผลิตรายเดียวสถานการณ์คิวผู้บริโภคหนึ่งตัว xchg soft barrier สามารถบังคับให้บรรทัดของโค้ดก่อน lazySet (ลำดับ + 1) สำหรับเธรดผู้ผลิตก่อนที่โค้ดเธรดผู้บริโภคใด ๆ ที่จะใช้ (ทำงานบน) ข้อมูลใหม่แน่นอน เธรดผู้บริโภคจะต้องตรวจสอบแบบอะตอมว่าลำดับผู้ผลิตเพิ่มขึ้นทีละหนึ่งโดยใช้ CompareAndSet (ลำดับ, ลำดับ + 1)

ฉันติดตามซอร์สโค้ด Hotspot เพื่อค้นหาการแมปที่แน่นอนของรหัส lazySet กับ cpp: http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/prims/unsafe cpp Unsafe_setOreledLong -> นิยาม SET_FIELD_VOLATILE -> OrderAccess: release_store_fence สำหรับ x86_64 OrderAccess: release_store_fence ถูกกำหนดโดยใช้คำสั่ง xchg

คุณสามารถดูว่ามันถูกกำหนดไว้อย่างไรใน jdk7 (doug lea กำลังทำงานกับสิ่งใหม่ ๆ สำหรับ JDK 8): http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/4fc084dac61e/src/os_cpu/ linux_x86 / เมล์ / orderAccess_linux_x86.inline.hpp

คุณยังสามารถใช้ hdis เพื่อถอดประกอบการทำงานของรหัส lazySet

มีคำถามอื่นที่เกี่ยวข้อง: เราต้องการ mfence เมื่อใช้ xchg หรือไม่


5
ยากที่จะเข้าใจว่าคุณได้รับอะไรจากที่นี่ คุณช่วยชี้แจงประเด็นของคุณได้ไหม
Paul Bellora

3
"lazySet == unsafe.putOrderLong == xchg rw (คำสั่ง asm ที่ทำหน้าที่เป็น soft barrier ซึ่งคิดราคา 20 รอบบน nehelem intel cpu) บน x86 (x86_64) อุปสรรคดังกล่าวมีประสิทธิภาพที่ถูกกว่ามากกว่า volatile หรือ AtomicLong getAndAdd" -> นี่ไม่เป็นความจริงสำหรับความรู้ที่ดีที่สุดของฉัน lazySet / putOrder คือ MOV ไปยังแอดเดรสซึ่งเป็นสาเหตุที่ตำราอาหาร JMM อธิบายว่าเป็น no-op บน x86
Nitsan Wakart

11

คุณสามารถดูการอภิปรายที่กว้างขึ้นเกี่ยวกับต้นกำเนิดและยูทิลิตี้ของ lazySet และ putOrder พื้นฐานได้ที่นี่: http://psy-lob-saw.blogspot.co.uk/2012/12/atomiclazyset-is-performance-win-for.html

เพื่อสรุป: lazySet เป็นการเขียนที่มีความผันผวนอย่างอ่อนในแง่ที่ว่ามันทำหน้าที่เป็นร้านค้าร้านค้าไม่ใช่รั้วเก็บของ สิ่งนี้ทำให้ lazySet ถูกคอมไพล์ JIT เป็นคำสั่ง MOV ที่คอมไพเลอร์ไม่สามารถสั่งซื้อใหม่ได้แทนที่จะเป็นคำสั่งที่แพงกว่าอย่างมีนัยสำคัญที่ใช้สำหรับชุดที่ผันผวน

เมื่ออ่านค่าคุณมักจะทำการอ่านแบบระเหย (ด้วย Atomic * .get () ไม่ว่าในกรณีใด ๆ )

lazySet เสนอกลไกการเขียนแบบระเหยที่สอดคล้องกันสำหรับนักเขียนคนเดียวกล่าวคือถูกต้องตามกฎหมายอย่างสมบูรณ์สำหรับนักเขียนคนเดียวที่จะใช้ lazySet เพื่อเพิ่มตัวนับเธรดหลายเธรดที่เพิ่มตัวนับเดียวกันจะต้องแก้ไขการเขียนที่แข่งขันกันโดยใช้ CAS ซึ่งเป็นสิ่งที่เกิดขึ้นภายใต้ หน้าปกของ Atomic * สำหรับ incAndGet


ว่าทำไมเราไม่สามารถพูดได้ว่านี้คือการที่ง่ายStoreStoreอุปสรรค แต่ไม่StoreLoad ?
Eugene

8

จากสรุปแพ็คเกจอะตอมพร้อมกัน

lazySetมีเอฟเฟกต์หน่วยความจำของการเขียน (กำหนด) ตัวแปรที่ระเหยได้ยกเว้นว่าจะอนุญาตให้จัดลำดับใหม่ด้วยการดำเนินการหน่วยความจำที่ตามมา (แต่ไม่ใช่ก่อนหน้า) ที่ไม่ได้กำหนดข้อ จำกัด ในการจัดลำดับใหม่ด้วยการเขียนแบบไม่ลบเลือนธรรมดา ในบริบทการใช้งานอื่น ๆ lazySet อาจนำไปใช้เมื่อลบข้อมูลออกเพื่อประโยชน์ในการรวบรวมขยะการอ้างอิงที่ไม่สามารถเข้าถึงได้อีก

หากคุณอยากรู้เกี่ยวกับ lazySet คุณก็ต้องมีคำอธิบายอื่น ๆ เช่นกัน

เอฟเฟกต์หน่วยความจำสำหรับการเข้าถึงและอัพเดตของอะตอมโดยทั่วไปจะเป็นไปตามกฎสำหรับ volatiles ดังที่ระบุไว้ในส่วนที่ 17.4 ของข้อกำหนดภาษา Java ™

getมีเอฟเฟกต์หน่วยความจำของการอ่านตัวแปรระเหย

setมีเอฟเฟกต์หน่วยความจำของการเขียน (กำหนด) ตัวแปรที่ระเหยได้

lazySetมีเอฟเฟกต์หน่วยความจำของการเขียน (กำหนด) ตัวแปรที่ระเหยได้ยกเว้นว่าจะอนุญาตให้มีการจัดลำดับใหม่ด้วยการดำเนินการหน่วยความจำที่ตามมา (แต่ไม่ใช่ก่อนหน้า) ที่ไม่ได้กำหนดข้อ จำกัด ในการจัดลำดับใหม่ด้วยการเขียนแบบไม่ลบเลือนธรรมดา ในบริบทการใช้งานอื่น ๆ lazySet อาจนำไปใช้เมื่อลบข้อมูลออกเพื่อประโยชน์ในการรวบรวมขยะการอ้างอิงที่ไม่สามารถเข้าถึงได้อีก

อ่อนแอ CompareAndSetอ่านและเขียนตัวแปรตามเงื่อนไขแบบมีเงื่อนไข แต่ไม่ได้สร้างคำสั่งที่เกิดขึ้นก่อนดังนั้นจึงไม่รับประกันเกี่ยวกับการอ่านและการเขียนก่อนหน้าหรือตามมาของตัวแปรใด ๆ ที่นอกเหนือจากเป้าหมายของจุดอ่อนของ CompareAndSet

CompareAndSetและการดำเนินการอ่านและอัปเดตอื่น ๆ ทั้งหมดเช่น getAndIncrement มีผลหน่วยความจำของทั้งการอ่านและการเขียนตัวแปรระเหย


4

นี่คือความเข้าใจของฉันแก้ไขฉันถ้าฉันผิด: คุณสามารถคิดว่าlazySet()เป็น "กึ่ง" ระเหย: โดยพื้นฐานแล้วมันเป็นตัวแปรที่ไม่ลบเลือนในแง่ของการอ่านโดยเธรดอื่นกล่าวคือค่าที่ตั้งโดย lazySet อาจไม่ปรากฏให้ผู้อื่นเห็น หัวข้อ แต่จะมีความผันผวนเมื่อมีการดำเนินการเขียนอื่นเกิดขึ้น (อาจมาจากเธรดอื่น) ผลกระทบเพียงหนึ่งเดียวของ lazySet compareAndSetฉันสามารถจินตนาการเป็น ดังนั้นถ้าคุณใช้lazySet(), get()จากหัวข้ออื่น ๆ อาจจะยังคงได้รับค่าเก่า แต่compareAndSet()มักจะมีค่าใหม่เพราะมันเป็นงานเขียน


1
คุณไม่ได้หมายความว่าcompareAndSet?
Dave Moten

2

Re: พยายามที่จะโง่ลง -

คุณสามารถคิดว่านี่เป็นวิธีการรักษาฟิลด์ที่มีความผันผวนราวกับว่ามันไม่ผันผวนสำหรับการดำเนินการเฉพาะร้านค้า (เช่น: ref = null;)

นั่นไม่ถูกต้องสมบูรณ์ แต่ก็น่าจะเพียงพอที่คุณจะตัดสินใจได้ระหว่าง "ตกลงฉันไม่สนใจจริงๆ" กับ "อืมขอฉันคิดสักหน่อย"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.