บูลีนระเหยกับ AtomicBoolean


244

AtomicBoolean ทำอะไรที่บูลีนระเหยไม่สามารถบรรลุได้


16
ฉันกำลังมองหาคำตอบที่เหมาะสมยิ่งขึ้นสำหรับ: "ข้อ จำกัด ของแต่ละข้อคืออะไร" ตัวอย่างเช่นถ้าเป็นค่าสถานะที่กำหนดโดยหนึ่งเธรดและอ่านโดยอย่างน้อยหนึ่งรายการอื่น ๆ ไม่จำเป็นต้องใช้ AtomicBoolean อย่างไรก็ตามตามที่ฉันเห็นด้วยคำตอบเหล่านี้หากเธรดกำลังแชร์ตัวแปรในหลายเธรดสามารถเขียนและดำเนินการตามผลลัพธ์ของการอ่าน AtomicBoolean นำการดำเนินการที่ไม่ใช่ล็อคประเภท CAS เข้ามาเล่น ที่จริงฉันเรียนรู้อยู่ที่นี่นิดหน่อย หวังว่าคนอื่นจะได้รับประโยชน์เช่นกัน
JeffV

1
ความเป็นไปได้ที่ซ้ำซ้อนของบูลีนระเหยกับ AtomicBoolean
Flow

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

คำตอบ:


99

พวกมันต่างกันโดยสิ้นเชิง ลองพิจารณาตัวอย่างของvolatileจำนวนเต็มนี้:

volatile int i = 0;
void incIBy5() {
    i += 5;
}

หากสองเธรดเรียกใช้ฟังก์ชันพร้อมกันiอาจเป็น 5 หลังจากนั้นเนื่องจากโค้ดที่คอมไพล์จะคล้ายกับสิ่งนี้ (ยกเว้นคุณไม่สามารถซิงโครไนซ์ได้int):

void incIBy5() {
    int temp;
    synchronized(i) { temp = i }
    synchronized(i) { i = temp + 5 }
}

หากตัวแปรมีความผันผวนการเข้าถึงแบบอะตอมมิกทุกครั้งจะถูกซิงโครไนซ์ แต่ก็ไม่ชัดเจนเสมอไปว่าสิ่งใดที่มีคุณสมบัติเป็นการเข้าถึงแบบอะตอมมิก ด้วยAtomic*วัตถุรับประกันว่าทุกวิธีคือ "atomic"

ดังนั้นหากคุณใช้AtomicIntegerและคุณสามารถมั่นใจได้ว่าผลจะเป็นgetAndAdd(int delta) 10ในทำนองเดียวกันถ้าทั้งสองเธรดคัดค้านbooleanตัวแปรพร้อมกันโดยAtomicBooleanคุณสามารถมั่นใจได้ว่ามันมีค่าดั้งเดิมหลังจากนั้นด้วย a volatile booleanคุณไม่สามารถทำได้

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

วัตถุประสงค์ของการvolatileเป็นที่แตกต่างกัน ลองพิจารณาตัวอย่างนี้

volatile boolean stop = false;
void loop() {
    while (!stop) { ... }
}
void stop() { stop = true; }

หากคุณมีการรันเธรดloop()และการเรียกเธรดอื่นstop()คุณอาจเรียกใช้การวนซ้ำไม่สิ้นสุดหากคุณละเว้นvolatileเนื่องจากเธรดแรกอาจแคชค่าหยุด ที่นี่volatileคำแนะนำสำหรับคอมไพเลอร์จะต้องระมัดระวังในการปรับแต่งให้ดีขึ้น


84
-1: คุณกำลังยกตัวอย่าง แต่ไม่ได้อธิบายความแตกต่างระหว่างสารระเหยกับ Atomicxxxx
Jason S

70
volatileคำถามคือไม่ได้เกี่ยวกับ คำถามคือเกี่ยวกับVSvolatile boolean AtomicBoolean
dolmen

26
-1: คำถามที่ถามโดยเฉพาะเกี่ยวกับบูลีนซึ่งเป็นกรณีที่ไม่ซ้ำกันเมื่อเทียบกับชนิดข้อมูลอื่น ๆ และควรจะอธิบายโดยตรง
John Haager

8
@ sgp15 เกี่ยวข้องกับการซิงโครไนซ์ของ Java 5
Man of One Way

6
หากค่าบูลีนถูกอ่านโดยเธรดจำนวนมาก แต่เขียนโดยเธรดเดียวเท่านั้นvolatile booleanนั่นก็เพียงพอแล้ว AtomicBooleanหากยังมีนักเขียนหลายคนคุณอาจต้อง
StvnBrkdll

263

ฉันใช้เขตข้อมูลระเหยเมื่อเขตข้อมูลกล่าวว่ามีการปรับปรุงโดยเธรดเจ้าของเท่านั้นและค่าถูกอ่านโดยเธรดอื่นเท่านั้นคุณสามารถคิดว่ามันเป็นสถานการณ์เผยแพร่ / สมัครสมาชิกที่มีผู้สังเกตการณ์จำนวนมาก แต่มีผู้เผยแพร่เพียงคนเดียว อย่างไรก็ตามหากผู้สังเกตการณ์เหล่านั้นต้องปฏิบัติตามตรรกะบางอย่างตามค่าของสนามแล้วผลักกลับค่าใหม่จากนั้นฉันก็ไปกับ Atomic * vars หรือล็อคหรือบล็อกซิงโครไนซ์ไม่ว่าอะไรจะเหมาะกับฉันที่สุด ในสถานการณ์ที่เกิดขึ้นพร้อมกันหลายอย่างมันจะเดือดลงเพื่อรับค่าให้เปรียบเทียบกับอีกสถานการณ์หนึ่งและอัพเดทหากจำเป็นดังนั้นเมธอด comparAndSet และ getAndSet จะปรากฏในคลาส Atomic *

ตรวจสอบ JavaDocs ของแพคเกจjava.util.concurrent.atomicสำหรับรายการของคลาส Atomic และคำอธิบายที่ยอดเยี่ยมเกี่ยวกับวิธีการทำงานของมัน (เพิ่งรู้ว่าพวกเขาไม่ล็อคดังนั้นจึงมีข้อดีเหนือล็อคหรือบล็อกที่ซิงโครไนซ์)


1
@ksl ผมคิดว่า @teto ต้องการที่จะอธิบายว่าถ้าเพียงหนึ่งหัวข้อแก้ไขbooleanvar volatile booleanเราควรเลือก
znlyj

2
สรุปยอดเยี่ยม
Ravindra babu

56

คุณไม่สามารถทำcompareAndSet, getAndSetการดำเนินงานของอะตอมกับบูลระเหย (ยกเว้นกรณีของหลักสูตรที่คุณประสาน)


6
นี่เป็นเรื่องจริง แต่สิ่งนี้จะไม่เป็นความต้องการที่หายากสำหรับบูลีนหรือไม่?
Robin

1
@Robin คิดว่าใช้มันเพื่อควบคุมการเรียกใช้วิธีการเริ่มต้นที่ขี้เกียจ
Ustaman Sangat

จริงๆแล้วฉันคิดว่านี่เป็นหนึ่งในกรณีการใช้งานหลัก
fool4jesus

42

AtomicBooleanมีวิธีการดำเนินการผสมของพวกเขาเป็นอะตอมและไม่ต้องใช้synchronizedบล็อก ในทางกลับกันvolatile booleanสามารถดำเนินการผสมได้หากทำได้ภายในsynchronizedบล็อก

ผลกระทบหน่วยความจำของการอ่าน / เขียนvolatile booleanเหมือนกับgetและsetวิธีการAtomicBooleanตามลำดับ

ตัวอย่างเช่นcompareAndSetวิธีที่จะดำเนินการตามปกติในอะตอม (ไม่มีsynchronizedบล็อก):

if (value == expectedValue) {
    value = newValue;
    return true;
} else {
    return false;
}

ดังนั้นcompareAndSetวิธีการนี้จะช่วยให้คุณเขียนโค้ดที่รับประกันว่าจะรันเพียงครั้งเดียวแม้ว่าจะถูกเรียกจากหลายเธรด ตัวอย่างเช่น:

final AtomicBoolean isJobDone = new AtomicBoolean(false);

...

if (isJobDone.compareAndSet(false, true)) {
    listener.notifyJobDone();
}

รับประกันว่าจะแจ้งให้ผู้ฟังทราบเพียงครั้งเดียว (สมมติว่าไม่มีเธรดอื่นตั้งค่าAtomicBooleanกลับไปเป็นfalseอีกครั้งหลังจากที่ตั้งค่าเป็นtrue)


14

volatileคำหลักรับประกันว่าเกิดขึ้นก่อนความสัมพันธ์ระหว่างเธรดที่แชร์ตัวแปรนั้น ไม่รับประกันว่าจะมี 2 กระทู้หรือมากกว่านั้นจะไม่รบกวนซึ่งกันและกันขณะเข้าถึงตัวแปรบูลีน


14
การเข้าถึงบูลีน (ในรูปแบบดั้งเดิม) เป็นอะตอมมิกใน Java ทั้งการอ่านและการมอบหมาย ดังนั้นไม่มีเธรดอื่นจะ "ขัดจังหวะ" การดำเนินการบูลีน
Maciej Biłas

1
ฉันขอโทษ แต่สิ่งนี้ตอบคำถามได้อย่างไร Atomic*ระดับ wraps volatileฟิลด์
สีเทา

CPU ไม่ได้แคชปัจจัยหลักในการตั้งค่าความผันผวนหรือไม่ เพื่อให้แน่ใจว่าค่าที่อ่านเป็นจริงสิ่งที่มันถูกตั้งค่าให้ล่าสุด
jocull

8

บูลีนระเหยกับ AtomicBoolean

คลาส Atomic * จะตัดค่าดั้งเดิมของชนิดเดียวกัน จากแหล่งที่มา:

public class AtomicLong extends Number implements java.io.Serializable {
   ...
   private volatile long value;
   ...
   public final long get() {
       return value;
   }
   ...
   public final void set(long newValue) {
       value = newValue;
   }

ดังนั้นหากสิ่งที่คุณทำคือการได้รับและการตั้งค่า Atomic * คุณก็อาจมีเขตข้อมูลระเหยแทน

AtomicBoolean ทำอะไรที่บูลีนระเหยไม่สามารถบรรลุได้

เรียน * อะตอมให้คุณวิธีการที่ให้การทำงานที่สูงขึ้นเช่นincrementAndGet(),compareAndSet()และอื่น ๆ ที่ใช้การดำเนินงานหลาย (รับ / เพิ่ม / ชุดทดสอบ / ชุด) โดยไม่ได้ล็อค นั่นเป็นเหตุผลที่คลาส Atomic * นั้นทรงพลัง

ตัวอย่างเช่นหากมีหลายเธรดที่ใช้รหัสต่อไปนี้โดยใช้ ++จะมีเงื่อนไขการแข่งขันเนื่องจาก++เป็นจริง: รับเพิ่มและตั้งค่า

private volatile value;
...
// race conditions here
value++;

อย่างไรก็ตามรหัสต่อไปนี้จะทำงานในสภาพแวดล้อมแบบมัลติเธรดได้อย่างปลอดภัยโดยไม่ต้องล็อค:

private final AtomicLong value = new AtomicLong();
...
value.incrementAndGet();

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


5

หากมีหลายเธรดที่เข้าถึงตัวแปรระดับคลาสดังนั้นแต่ละเธรดสามารถเก็บสำเนาของตัวแปรนั้นไว้ในแคช threadlocal

การทำให้ตัวแปรระเหยง่ายจะป้องกันไม่ให้เธรดเก็บสำเนาของตัวแปรไว้ในแคชโลคอล

ตัวแปรอะตอมนั้นแตกต่างกันและอนุญาตให้แก้ไขค่าของอะตอมได้


4

บูลีนดึกดำบรรพ์เป็นอะตอมมิกสำหรับการเขียนและการอ่านการระเหยรับประกันหลักการที่เกิดขึ้นก่อน ดังนั้นหากคุณต้องการ get () และ set () อย่างง่ายคุณไม่จำเป็นต้องใช้ AtomicBoolean

ในทางตรงกันข้ามถ้าคุณจำเป็นต้องใช้การตรวจสอบบางอย่างก่อนที่จะตั้งค่าของตัวแปรเช่น "ถ้าเป็นจริงแล้วตั้งค่าเป็นเท็จ" จากนั้นคุณจะต้องดำเนินการนี้ atomically เช่นกันในกรณีนี้ใช้ comparAndSet และวิธีการอื่น ๆ AtomicBoolean เนื่องจากถ้าคุณพยายามใช้ตรรกะนี้ด้วยบูลีนที่ระเหยคุณจะต้องมีการซิงโครไนซ์บางอย่างเพื่อให้แน่ใจว่าค่าไม่เปลี่ยนแปลงระหว่างการรับและการตั้งค่า


3

จำ IDIOM -

อ่าน - แก้ไข - เขียนสิ่งนี้คุณไม่สามารถทำได้ด้วยความผันผวน


2
สั้นกรอบและตรงประเด็น volatileใช้งานได้เฉพาะในกรณีที่เธรดเจ้าของมีความสามารถในการอัปเดตค่าฟิลด์และเธรดอื่นสามารถอ่านได้เท่านั้น
Chaklader Asfak Arefe

3

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

AtomicBooleanแต่ถ้าคุณมีหลายหัวข้อการปรับเปลี่ยนแบบบูลที่คุณควรใช้ มิฉะนั้นรหัสต่อไปนี้ไม่ปลอดภัย:

boolean r = !myVolatileBoolean;

การดำเนินการนี้ทำได้สองขั้นตอน:

  1. ค่าบูลีนถูกอ่าน
  2. เขียนค่าบูลีน

หากเธรดอื่นแก้ไขค่าระหว่าง#1และ2#คุณอาจได้รับผลลัพธ์ที่ผิด AtomicBooleanวิธีการหลีกเลี่ยงปัญหานี้โดยทำตามขั้นตอน#1และ#2atomically


-1

ทั้งคู่มีแนวคิดเดียวกัน แต่ในบูลีนแบบอะตอมมิกมันจะให้อะตอมมิกซิตี้แก่การทำงานในกรณีที่สวิตช์ซีพียูเกิดขึ้นระหว่างนั้น

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