เธรดคลาสสุ่มปลอดภัยหรือไม่?


110

การแชร์อินสแตนซ์ของRandomคลาสระหว่างเธรดหลายเธรดถูกต้องหรือไม่ และการโทรnextInt(int)จากหลายเธรดโดยเฉพาะ?


@Bala R ไม่เราไม่ได้พูดถึง Random object ของ C # แต่เป็นของ Java
Buhake Sindi

อ๊ะ. ขออภัยที่พลาดส่วนนั้นไป
Bala R

การใช้การสุ่มเพื่อรับตัวเลขในสภาพแวดล้อมแบบมัลติเธรดอาจให้ผลลัพธ์ที่ไม่ดีได้บางทีมันอาจจะไม่สำคัญ แต่ถ้าคุณกำลังทำแบบจำลองอยู่ก็เป็นเรื่องดีที่จะรู้
Maxence SCHMITT

14
สำหรับผู้อ่านเพิ่มเติม: มีชั้นเรียนใหม่ 1.7 java.util.concurrent.ThreadLocalRandomชื่อ
Jin Kwon

คำตอบ:


66

เป็นเธรดที่ปลอดภัยในแง่ที่มันจะยังคงสร้างตัวเลขสุ่มเมื่อใช้โดยเธรดหลาย

การใช้งาน Sun / Oracle JVM ใช้ซิงโครไนซ์และ AtomicLong เป็นเมล็ดพันธุ์เพื่อปรับปรุงความสอดคล้องกันระหว่างเธรด แต่ดูเหมือนว่าจะไม่สามารถรับประกันได้ในทุกแพลตฟอร์มในเอกสารประกอบ

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


69
เพิ่มการรับประกันในเอกสาร Java 7: "อินสแตนซ์ของ java.util.Random is threadsafe" docs.oracle.com/javase/7/docs/api/java/util/Random.html
Matt R


8

ตามเอกสารประกอบMath.random ()รับประกันว่าปลอดภัยสำหรับการใช้งานหลายเธรด แต่คลาสสุ่มไม่มี ฉันจะถือว่าคุณจะต้องซิงโครไนซ์ด้วยตัวเอง


7

ใช่สุ่มเธรดปลอดภัย nextInt()เรียกวิธีป้องกันnext(int)วิธีการที่ใช้AtomicLong seed, nextseed(ยาวอะตอม) เพื่อสร้างเมล็ดพันธุ์ต่อไป AtomicLongใช้เพื่อความปลอดภัยของเกลียวในการสร้างเมล็ดพันธุ์


6

ตามที่กล่าวไว้ว่าเป็นการบันทึกเธรด แต่ก็ควรใช้java.util.concurrent.ThreadLocalRandomตามบทความนี้ (ลิงค์ตาย) ThreadLocalRandom ยังเป็นคลาสย่อยของ Random ดังนั้นจึงเข้ากันได้แบบย้อนกลับ

บทความที่เชื่อมโยงเทียบ profiling ผลของการเรียนแบบสุ่มที่แตกต่างกันjava.util.Random, และjava.util.concurrent.ThreadLocalRandom java.lang.ThreadLocal<java.util.Random>ผลการวิจัยพบว่าการใช้งาน ThreadLocalRandom มีประสิทธิภาพมากที่สุดตามด้วย ThreadLocal และการสุ่มที่แย่ที่สุด


4

ไม่มีเหตุผลที่หลายเธรดไม่สามารถใช้ Random เดียวกันได้ทั้งหมด อย่างไรก็ตามเนื่องจากคลาสไม่ปลอดภัยต่อเธรดอย่างชัดเจนและรักษาลำดับของตัวเลขสุ่มหลอกผ่านเมล็ดพันธุ์ หลายเธรดอาจจบลงด้วยหมายเลขสุ่มเดียวกัน มันจะดีกว่าถ้าสร้าง Randoms หลาย ๆ ตัวสำหรับแต่ละเธรดและเพาะเมล็ดให้ต่าง

แก้ไข : ฉันเพิ่งสังเกตเห็นว่าการใช้งาน Sun ใช้ AtomicLong ดังนั้นฉันเดาว่าเป็นเธรดที่ปลอดภัย (ตามที่ระบุไว้โดย Peter Lawrey (+1))

แก้ไข 2 : OpenJDK ยังใช้ AtomicLong สำหรับเมล็ดพันธุ์ อย่างที่คนอื่น ๆ บอกแม้ว่าจะยังไม่ดีที่จะพึ่งพาสิ่งนี้


3

นี่คือวิธีที่ฉันจัดการกับปัญหาโดยไม่คิดว่า 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)ส่วนสำคัญหรือไม่?
Jin Kwon

1
ใช่นั่นเป็นการแก้ไขที่สกปรก นั่น(24*60*60*1000)คือเพื่อให้เธรดที่มี ID 12ที่xxxxxxxxxx045มิลลิวินาทีไม่ได้รับการเพาะเมล็ดเหมือนกับเธรด22ที่xxxxxxxxxx035มิลลิวินาที อย่างไรก็ตามฉันไม่มีเหตุผลที่ดีที่จะคิดว่า ID เธรดนั้นเพิ่มขึ้นและไม่มีเหตุผลที่ดีที่จะคิดว่าฉันกำลังสร้างเธรดในเวลาสุ่มมากกว่าวันนี้ ฉันทำให้ alg ง่ายขึ้นตอนนี้และอัปเดตคำอธิบายเพื่อระบุข้อบกพร่อง
Ryan

0

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

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