เมื่อไหร่ที่คุณจะเรียก thread.run () ของ java แทน thread.start ()?


109

คุณจะเรียก Java thread.run()แทนเมื่อthread.start()ใด


47
เมื่อฉันเป็น thread.start () วิธีการ? :)
Bill the Lizard

3
@blank คำตอบคือt.run()เมื่อคุณต้องการเรียกใช้tงานบนเธรดปัจจุบันและt.start()เมื่อคุณต้องการรันtงานบนเธรดtเอง หรือคุณกำลังถามหากรณีการใช้งานจริง?
Pacerier

2
เมื่อคุณเป็นคนงี่เง่าและต้องการใช้เวลาหนึ่งชั่วโมงในการดีบักโค้ดมัลติเธรดเพียงเพื่อจะได้รู้ในภายหลังว่าคุณควรโทรไปแล้วstart()! อย่างฉัน ... วิธีนี้ไม่ควรเปิดเผยต่อสาธารณะ!
Pierre Henry

คำตอบ:


113

คุณอาจต้องการเรียก run () ในการทดสอบหน่วยเฉพาะที่เกี่ยวข้องกับฟังก์ชันการทำงานอย่างเคร่งครัดไม่ใช่การทำงานพร้อมกัน


95

ไม่เลย การเรียก run () โดยตรงเพียงแค่รันโค้ดแบบซิงโครนัส (ในเธรดเดียวกัน) เช่นเดียวกับการเรียกใช้เมธอดปกติ


25
"ไม่เคย" เด็ดขาดเกินไปหน่อย อาจไม่ต้องการเธรดใหม่เสมอไปและยังคงรันโค้ดอยู่?
Tomalak

4
อาจจะ แต่ในกรณีนั้นการสร้างเธรดใหม่เพียงเพื่อเรียกใช้เมธอด run () เท่านั้นโดยไม่จำเป็น ดีกว่าที่จะสร้าง Runnable im และเรียกใช้ในเธรดนั้นหรือสร้างและเริ่มเธรดใหม่ด้วยมัน
Scott Bale

1
แค่ทบทวน ... ถ้าไม่เคยทำไมวิธีนี้จึงเป็นแบบสาธารณะ?
ว่าง

4
เป็นสาธารณะเนื่องจาก Thread ใช้ Runnable คุณสามารถ subclass Thread และแทนที่ run () ซึ่งมีผลเช่นเดียวกับการใส่โค้ดของคุณใน Runnable และส่งผ่านไปยังตัวสร้างเธรด วิธีปฏิบัติที่ดีกว่าในการใช้อ็อบเจ็กต์ Runnable แยกต่างหากเนื่องจากจะทำให้คุณมีความยืดหยุ่นมากขึ้น (เช่นส่งต่อไปยัง Executor เป็นต้น)
Adam Crume

2
ให้ฉันยกตัวอย่างที่เป็นรูปธรรมที่ฉันกำลังทำงานอยู่: ฉันมีโปรแกรมที่สามารถเรียกใช้เป็น GUI หรือจากบรรทัดคำสั่ง ในกรณี GUI ฉันต้องการให้ออบเจ็กต์ที่ทำหน้าที่ในการยกของหนักทำงานบนเธรดแยกต่างหากและส่งการอัปเดตไปยัง gui ในโหมดบรรทัดคำสั่งฉันไม่ต้องการเธรดแยกนั้น
Edward Falk

27

ในรูปแบบรหัสเธรด Java คำถามที่พบบ่อย :

ถาม: เมธอด start () และ run () ของเธรดต่างกันอย่างไร

ตอบ: เมธอด start () และ run () แยกกันในคลาส Thread มีสองวิธีในการสร้างโปรแกรมเธรด เมธอด start () เริ่มการทำงานของเธรดใหม่และเรียกใช้เมธอด run () เมธอด start () จะส่งคืนทันทีและเธรดใหม่จะทำงานต่อไปจนกว่าเมธอด run () จะกลับมา

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

ขึ้นอยู่กับลักษณะของโปรแกรมเธรดของคุณการเรียกใช้เมธอด Thread run () โดยตรงสามารถให้เอาต์พุตเหมือนกับการเรียกผ่านเมธอด start () แต่ในกรณีหลังโค้ดจะถูกเรียกใช้งานจริงในเธรดใหม่


thread's run() method executes the run() method of the Runnable object in the new thread instead.นั่นไม่เป็นความจริง (หรืออย่างน้อยซอร์สโค้ด Java 8 ของฉันก็บอกเป็นอย่างอื่น) แต่น่าเสียดายที่ลิงก์ดูเหมือนจะเสียดังนั้นฉันจึงรายงานข้อผิดพลาดที่นี่แทน
kajacx

1
@ โทมะลักษณ์นี้ไม่ตอบคำถามที่ถาม คำถามคือไม่ได้ขอความแตกต่าง แต่ถามเกี่ยวกับกรณีการใช้งานโดยเราจะเรียกแทนthread.run() thread.start()
Pacerier

24

การดำเนินการthread.run()ไม่ได้สร้างรหัสใหม่Threadที่จะเรียกใช้งาน เพียงแค่รันโค้ดในเธรดปัจจุบันที่thread.run()มีการเรียกใช้โค้ด

การดำเนินการthread.start()จะสร้างเธรดระดับระบบปฏิบัติการใหม่ซึ่งrun()วิธีการเรียกใช้

ในสาระสำคัญ:

การเขียนโปรแกรมแบบเธรดเดียว→เรียกใช้run()เมธอดโดยตรง

การเขียนโปรแกรมหลายเธรด→การเรียกใช้start()เมธอด

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


13

สิ่งนี้ถูกพาดพิงไปแล้ว แต่เพื่อความชัดเจน: การสร้างวัตถุ Thread ใหม่เพื่อเรียกมันว่า run () method นั้นมีราคาแพงโดยไม่จำเป็นและควรเป็นธงสีแดงที่สำคัญ มันจะเป็นการดีกว่ามากและการออกแบบที่แยกออกจากกันมากขึ้นในการสร้าง Runnable im และ (a) เรียกมันว่า run () method โดยตรงหากนั่นเป็นพฤติกรรมที่ต้องการหรือ (b) สร้าง Thread ใหม่ด้วย Runnable นั้นและเริ่มต้น Thread

ยังดีกว่าสำหรับการแยกส่วนเพิ่มเติมให้ตรวจสอบอินExecutorเทอร์เฟซและเฟรมเวิร์กใน JDK 5 และใหม่กว่า สิ่งนี้ช่วยให้คุณสามารถแยกการดำเนินการงาน (อินสแตนซ์ Runnable) จากวิธีดำเนินการ (การใช้งาน Executor ซึ่งอาจเรียกใช้งาน Runnable ในเธรดปัจจุบันในเธรดใหม่โดยใช้เธรดที่มีอยู่จากพูล และอะไรไม่).


9

โทรก็จะเปิดในการโทรthread.start() thread.run()นึกไม่ออกว่าเมื่อไหร่ที่คุณอยากจะข้ามthread.start()และตรงไปที่thread.run()


3
ในระหว่างการทดสอบเป็นกรณีเดียวที่ถูกต้องตามกฎหมายที่ฉันคิดได้ มิฉะนั้นเนื้อหาของ run () ควรอยู่ในวิธีการแยกต่างหากที่เรียกโดย run หรือโดยวิธีอื่น
Bill the Lizard

9

การแยกstart()และrun()วิธีการในคลาสเธรดมีสองวิธีในการสร้างโปรแกรมเธรด start()วิธีการเริ่มต้นการดำเนินการของหัวข้อใหม่และเรียกrun()วิธีการ start()วิธีการส่งกลับทันทีและหัวข้อใหม่ได้ตามปกติต่อไปจนกว่าrun()วิธีการส่งกลับ

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

ขึ้นอยู่กับลักษณะของโปรแกรมเธรดของคุณการเรียกใช้run()เมธอดเธรดโดยตรงสามารถให้ผลลัพธ์เหมือนกับการเรียกใช้start()เมธอด แต่ในกรณีหลังโค้ดจะถูกเรียกใช้ในเธรดใหม่

เอกสารอ้างอิง


เช่นเดียวกับคำตอบ Tomalak !! หากอ้างอิงจากที่ใดกรุณาระบุ !!
Barry

The start() method returns immediately and the new thread normally continues until the run() method returns.หากstart()ส่งคืนทันทีว่าการrun()วิ่งยังคงเป็นเช่นไรเนื่องจากถูกเรียกตัวเองจากstart()
KNU

7

หากคำถามคือ - "เหตุใดจึงเรียกวิธีการเริ่มต้นเธรดแทนที่จะเรียกใช้เมธอดโดยตรง" ฉันได้ตอบด้วยโค้ดตัวอย่างด้านล่าง หวังว่าจะกระจ่าง ในตัวอย่างด้านล่าง:

/*
By calling t1.start(), 
we are getting the main calling thread returned immediately 
after the t1.start() called and is ready to proceed for other 
operations.And the thread t1 starts executing the run method of the object r. 
Hence the the output will be:

      I am the main thread , i created thread t1 and had it execute run method, which is currently looping from 0 to 1000000

      I am done executing run method of testThread

*/


/* If we call t1.run() instead of t1.start(), (just replace t1.start() with t1.run() in the code for testing)
 its like a regular method call and the main thread will not return until the run method completes, 
 hence the output will be:

         I am done executing run method of testThread

         I am the main thread , i created thread t1 and had it execute run method, which is currently looping for i to 1000000

*/


class testThread implements Runnable{

 public void run()
 {
     for(int i=0;i<1000000;i++){} //a simple delay block to clarify.

     System.out.println("I am done executing run method of testThread");

 }  
}

public class mainClass{

   public static void main(String [] args)
    {
          testThread r = new testThread();
          Thread t1 = new Thread(r);
          t1.start();  /* Question is: can we call instead t1.run() */  
          System.out.println("I am the main thread , i created thread t1 and had it execute run method, which is currently looping for i to 1000000");

    }
}

5

เมื่อคุณต้องการให้ทำงานพร้อมกัน การเรียกใช้วิธีการรันจะไม่ทำให้คุณมีมัลติเธรด วิธีการเริ่มต้นจะสร้างเธรดใหม่ซึ่งเรียกใช้เมธอดการรัน


3

หากคุณต้องการเรียกใช้งานเนื้อหาของ run () เช่นเดียวกับวิธีการอื่น ๆ ไม่เริ่มกระทู้แน่นอน


3

สมมติว่าคุณทราบวิธีการเริ่มต้นและรันเช่นซิงโครนัสกับอะซิงโครนัส วิธีการรันสามารถใช้เพื่อทดสอบการทำงาน

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


2

อย่างน้อยใน JVM 1.6 มีการตรวจสอบและเรียกใช้เล็กน้อยเรียกว่าเนทีฟ:

 public synchronized void start() {
        /**
     * This method is not invoked for the main method thread or "system"
     * group threads created/set up by the VM. Any new functionality added 
     * to this method in the future may have to also be added to the VM.
     *
     * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        start0();
        if (stopBeforeStart) {
        stop0(throwableFromStop);
    }
    }

    private native void start0();

2

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


-1
public class TestClass implements Runnable {
    public static void main(String[] args) {
        TestClass tc = new TestClass();

        Thread t1 = new Thread(tc);
        System.out.println("Before Starting Thread " + Thread.currentThread().hashCode());
        t1.start();
        System.out.println("After Starting Thread " + Thread.currentThread().hashCode());
    }

    @Override
    public void run() {
        System.out.println("TestClass Run method is  Running with thread " + Thread.currentThread().hashCode());        
    }
}

สวัสดี Frnz ลองดูและเรียกใช้ตัวอย่างข้างต้นเพื่อทำความเข้าใจอย่างชัดเจนครั้งแรกรันด้วย t1.start () และดู hashcode และครั้งต่อไปด้วย t1.run () และ chk hashcodes
Avatar Girase

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