วิธีการเริ่มต้นเธรดสองเธรดที่“ ตรงกัน” ในเวลาเดียวกัน


92

เธรดควรเริ่มต้นในเสี้ยววินาทีเดียวกัน ผมเข้าใจว่าถ้าคุณทำมันจะใช้เวลามิลลิวินาทีก่อนที่จะดำเนินการต่อไปของthread1.start()thread2.start()

มันเป็นไปได้หรือเป็นไปไม่ได้?


2
การแบ่งวินาทีเป็นเวลานานมากที่ความเร็ว GHz
Nikolai Fetissov

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

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

ฉันเดาว่าฉันเข้าใจความโกรธทั้งหมดของคุณ มันเป็นคำถามที่ถามฉันในการสัมภาษณ์ ... อาจจะเป็นการหลอกถาม แต่ฉันสับสนและต้องการยืนยัน นั่นเป็นเหตุผลที่ฉันถามว่ามันเป็นไปได้ไหม
figaro

2
@javaguy - ไม่ใช่คำถาม "หลอกลวง" เป็นคำถามที่เลือกเพื่อดูว่าคุณเข้าใจการเขียนโปรแกรมแบบมัลติเธรดโดยทั่วไปได้ดีเพียงใด ... เช่นกันในกรณี Java
Stephen C

คำตอบ:


136

ในการเริ่มต้นเธรดในเวลาเดียวกัน (อย่างน้อยที่สุดเท่าที่จะเป็นไปได้) คุณสามารถใช้CyclicBarrier :

// We want to start just 2 threads at the same time, but let's control that 
// timing from the main thread. That's why we have 3 "parties" instead of 2.
final CyclicBarrier gate = new CyclicBarrier(3);

Thread t1 = new Thread(){
    public void run(){
        gate.await();
        //do stuff    
    }};
Thread t2 = new Thread(){
    public void run(){
        gate.await();
        //do stuff    
    }};

t1.start();
t2.start();

// At this point, t1 and t2 are blocking on the gate. 
// Since we gave "3" as the argument, gate is not opened yet.
// Now if we block on the gate from the main thread, it will open
// and all threads will start to do stuff!

gate.await();
System.out.println("all threads started");

ไม่จำเป็นต้องเป็น a CyclicBarrierคุณสามารถใช้CountDownLatchหรือแม้แต่ตัวล็อก

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

บนแพลตฟอร์มอื่น ๆ หัวข้อที่เริ่มต้นว่าอาจจะเป็นความต้องการที่ถูกต้องมากครับ


5
+1 ดีความคิด ;-) แม้ว่าแน่นอนมันไม่ได้ทำให้หัวข้อเริ่มต้นที่ตรงเวลาเดียวกันในเวลาจริง (อย่างน้อยไม่ได้อยู่บนชิปแบบ single-core และไม่รับประกันแม้กระทั่งบนชิปแบบ multi-core) แต่ คิดไม่ออกว่าจะทำอย่างไรให้ดีขึ้น
David Z

สิ่งนี้จะจัดการกับการรอเฉพาะของสภาพแวดล้อมหรือไม่?
ChaosPandion

@ChaosPandion: สนใจที่จะอธิบาย?
ซานต้า

@Santa - ตัวอย่าง Win32 API มีแบบดั้งเดิมที่แตกต่างกัน CreateEventประเภทหนึ่งที่มีประโยชน์เป็นคู่มือการจัดกิจกรรมการตั้งค่าส่งกลับเมื่อคุณเรียก msdn.microsoft.com/en-us/library/ms686364%28VS.85%29.aspx
ChaosPandion

1
@ Zwei - ไม่ว่าจะเป็นอะไรก็ตามนี่คือคำตอบที่ฉันจะโพสต์หากฉันเป็นกูรู Java
ChaosPandion

15

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

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


1
คุณสามารถเข้าใกล้ได้ ทุกอย่างขึ้นอยู่กับเทคนิคการซิงโครไนซ์ที่คุณใช้และแน่นอนว่ามี CPU หรือคอร์มากกว่า 1 ตัว
ChaosPandion

แนวคิดก็คือว่านี่เป็นแนวทางที่ไม่ถูกต้องและไม่ควรมีความจำเป็นในสภาพแวดล้อมแบบเรียลไทม์ใด ๆ ไม่ใช่ว่า "ค่อนข้างใกล้เคียง"
Nikolai Fetissov

1
นอกจากนี้ยังเป็นไปไม่ได้เนื่องจากการตั้งเวลาเธรด Java ไม่ได้ให้ความแม่นยำในระดับมิลลิวินาที
Stephen C

1
@ Zwei - คุณอาจจะ "ใกล้เคียง" เกือบตลอดเวลาบนเครื่องที่ไม่ได้ใช้งาน แต่ถ้าคุณต้องการใช้งานตลอดเวลาคุณต้องตั้งโปรแกรมเป็นภาษาเช่น C บนเครื่องที่รองรับแบบเรียลไทม์ใน OS พิจารณาด้วยว่า JVM อาจเรียกใช้ GC เต็มรูปแบบใน "เสี้ยววินาที" ที่คุณต้องการเริ่มเธรดของคุณ
Stephen C

1
เป็นปัญหาการซิงโครไนซ์ที่ถูกต้องสมบูรณ์ เธรดจำเป็นต้องเริ่มต้นข้อมูลบางอย่างตรวจสอบให้แน่ใจว่าไม่มีใครเข้าไปในพื้นที่วิกฤตโดยไม่มีการตรวจสอบที่เหมาะสม และความจริงที่ว่า CyclicBerrier รวมอยู่ในแพ็คเกจพร้อมกันของ javas หมายความว่านี่เป็นปัญหาที่สำคัญ
Denis Tulskiy

14

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

import java.util.concurrent.CountDownLatch;


public class ThreadExample
{
    public static void main(String[] args) 
    {
        CountDownLatch latch = new CountDownLatch(1);
        MyThread t1 = new MyThread(latch);
        MyThread t2 = new MyThread(latch);
        new Thread(t1).start();
        new Thread(t2).start();
        //Do whatever you want
        latch.countDown();          //This will inform all the threads to start
        //Continue to do whatever
    }
}

class MyThread implements Runnable
{
    CountDownLatch latch;
    public MyThread(CountDownLatch latch) 
    {
        this.latch = latch;
    }
    @Override
    public void run() 
    {
        try 
        {
            latch.await();          //The thread keeps waiting till it is informed
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Do the actual thing
    }
}

คำตอบนี้จะได้รับประโยชน์จากตัวอย่างโค้ดน้อยลง
user2418306

6
  1. ตามที่ฉันเข้าใจ JVM ส่วนใหญ่มอบหมายสิ่งนี้ให้กับระบบปฏิบัติการ ดังนั้นคำตอบจะเป็นเฉพาะระบบปฏิบัติการ
  2. เป็นไปไม่ได้อย่างชัดเจนในเครื่องที่มีโปรเซสเซอร์เดียว
  3. มีความซับซ้อนมากขึ้นเมื่อเทียบกับเครื่องมัลติโปรเซสเซอร์ ตามทฤษฎีสัมพัทธภาพพร้อมกัน "เป็นไปไม่ได้ที่จะพูดในแง่ที่แน่นอนว่าเหตุการณ์สองเหตุการณ์เกิดขึ้นในเวลาเดียวกันหรือไม่หากเหตุการณ์เหล่านั้นถูกแยกออกจากกันในอวกาศ" ไม่ว่าโปรเซสเซอร์ของคุณจะอยู่ใกล้แค่ไหนหน่วยประมวลผลกลางเหล่านั้นก็แยกออกจากกันในอวกาศ
    1. หากคุณสามารถยอมรับความสัมพันธ์พร้อมกันได้ก็น่าจะง่ายกว่าเพียงแค่จำลองโดยใช้เทคนิคที่กล่าวถึงในคำตอบอื่น ๆ

1
... และแม้ว่าเราจะถือว่าการเริ่มต้นพร้อมกันแต่ละเธรดมีไทม์ไลน์ของตัวเองทั้งหมดนั้นทำงานพร้อมกันแต่ไม่จำเป็นต้องขนานกันดังนั้นสิ่งที่ใครบางคนสันนิษฐานเกี่ยวกับการทำงานพร้อมกันของเธรดสามารถ (จะ) เป็นโมฆะในนาโนวินาทีถัดไป (แล้วแต่อย่างใด timeline) …
Holger
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.