การแชร์อินสแตนซ์ของRandom
คลาสระหว่างเธรดหลายเธรดถูกต้องหรือไม่ และการโทรnextInt(int)
จากหลายเธรดโดยเฉพาะ?
java.util.concurrent.ThreadLocalRandom
ชื่อ
การแชร์อินสแตนซ์ของRandom
คลาสระหว่างเธรดหลายเธรดถูกต้องหรือไม่ และการโทรnextInt(int)
จากหลายเธรดโดยเฉพาะ?
java.util.concurrent.ThreadLocalRandom
ชื่อ
คำตอบ:
เป็นเธรดที่ปลอดภัยในแง่ที่มันจะยังคงสร้างตัวเลขสุ่มเมื่อใช้โดยเธรดหลาย
การใช้งาน Sun / Oracle JVM ใช้ซิงโครไนซ์และ AtomicLong เป็นเมล็ดพันธุ์เพื่อปรับปรุงความสอดคล้องกันระหว่างเธรด แต่ดูเหมือนว่าจะไม่สามารถรับประกันได้ในทุกแพลตฟอร์มในเอกสารประกอบ
ฉันจะไม่เขียนโปรแกรมของคุณเพื่อต้องการการรับประกันดังกล่าวโดยเฉพาะอย่างยิ่งเมื่อคุณไม่สามารถระบุลำดับที่nextInt()
จะเรียกได้
มันปลอดภัยแม้ว่ามันจะไม่เสมอไป
ดูhttp://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6362070สำหรับรายละเอียดเพิ่มเติม
ตามเอกสารประกอบMath.random ()รับประกันว่าปลอดภัยสำหรับการใช้งานหลายเธรด แต่คลาสสุ่มไม่มี ฉันจะถือว่าคุณจะต้องซิงโครไนซ์ด้วยตัวเอง
ใช่สุ่มเธรดปลอดภัย nextInt()
เรียกวิธีป้องกันnext(int)
วิธีการที่ใช้AtomicLong seed, nextseed
(ยาวอะตอม) เพื่อสร้างเมล็ดพันธุ์ต่อไป AtomicLong
ใช้เพื่อความปลอดภัยของเกลียวในการสร้างเมล็ดพันธุ์
ตามที่กล่าวไว้ว่าเป็นการบันทึกเธรด แต่ก็ควรใช้java.util.concurrent.ThreadLocalRandom
ตามบทความนี้ (ลิงค์ตาย) ThreadLocalRandom ยังเป็นคลาสย่อยของ Random ดังนั้นจึงเข้ากันได้แบบย้อนกลับ
บทความที่เชื่อมโยงเทียบ profiling ผลของการเรียนแบบสุ่มที่แตกต่างกัน
java.util.Random
, และjava.util.concurrent.ThreadLocalRandom
java.lang.ThreadLocal<java.util.Random>
ผลการวิจัยพบว่าการใช้งาน ThreadLocalRandom มีประสิทธิภาพมากที่สุดตามด้วย ThreadLocal และการสุ่มที่แย่ที่สุด
ไม่มีเหตุผลที่หลายเธรดไม่สามารถใช้ Random เดียวกันได้ทั้งหมด อย่างไรก็ตามเนื่องจากคลาสไม่ปลอดภัยต่อเธรดอย่างชัดเจนและรักษาลำดับของตัวเลขสุ่มหลอกผ่านเมล็ดพันธุ์ หลายเธรดอาจจบลงด้วยหมายเลขสุ่มเดียวกัน มันจะดีกว่าถ้าสร้าง Randoms หลาย ๆ ตัวสำหรับแต่ละเธรดและเพาะเมล็ดให้ต่าง
แก้ไข : ฉันเพิ่งสังเกตเห็นว่าการใช้งาน Sun ใช้ AtomicLong ดังนั้นฉันเดาว่าเป็นเธรดที่ปลอดภัย (ตามที่ระบุไว้โดย Peter Lawrey (+1))
แก้ไข 2 : OpenJDK ยังใช้ AtomicLong สำหรับเมล็ดพันธุ์ อย่างที่คนอื่น ๆ บอกแม้ว่าจะยังไม่ดีที่จะพึ่งพาสิ่งนี้
นี่คือวิธีที่ฉันจัดการกับปัญหาโดยไม่คิดว่า Random ใช้ตัวแปรอะตอม มันยังสามารถสุ่มชนกันได้หากcurrentTime * thread id
เวลาในอนาคตเท่ากัน แต่มันหายากพอสำหรับความต้องการของฉัน เพื่อหลีกเลี่ยงความเป็นไปได้ที่จะเกิดการชนกันอย่างแท้จริงคุณสามารถให้แต่ละคำขอรอการประทับเวลาของนาฬิกาที่ไม่ซ้ำกัน
/**
* Thread-specific random number generators. Each is seeded with the thread
* ID, so the sequence of pseudo-random numbers are unique between threads.
*/
private static ThreadLocal<Random> random = new ThreadLocal<Random>() {
@Override
protected Random initialValue() {
return new Random(
System.currentTimeMillis() *
Thread.currentThread().getId());
}
};
(24*60*60*1000)
ส่วนสำคัญหรือไม่?
(24*60*60*1000)
คือเพื่อให้เธรดที่มี ID 12
ที่xxxxxxxxxx045
มิลลิวินาทีไม่ได้รับการเพาะเมล็ดเหมือนกับเธรด22
ที่xxxxxxxxxx035
มิลลิวินาที อย่างไรก็ตามฉันไม่มีเหตุผลที่ดีที่จะคิดว่า ID เธรดนั้นเพิ่มขึ้นและไม่มีเหตุผลที่ดีที่จะคิดว่าฉันกำลังสร้างเธรดในเวลาสุ่มมากกว่าวันนี้ ฉันทำให้ alg ง่ายขึ้นตอนนี้และอัปเดตคำอธิบายเพื่อระบุข้อบกพร่อง
Random
ชั้นไม่ได้ตั้งค่าสำหรับหนึ่งตัวอย่างที่จะใช้ในหลายหัวข้อ แน่นอนว่าถ้าคุณทำเช่นนี้คุณจะเพิ่มความเป็นไปได้ที่จะไม่สามารถคาดเดาได้และเข้าใกล้ตัวเลขสุ่มมากขึ้น แต่เนื่องจากเป็นเครื่องกำเนิดไฟฟ้าแบบสุ่มหลอกฉันจึงไม่เห็นสาเหตุที่คุณต้องแชร์อินสแตนซ์ มีข้อกำหนดเฉพาะเพิ่มเติมหรือไม่?