อะไรคือความแตกต่างระหว่าง Thread start () และ Runnable run ()


224

สมมติว่าเรามี Runnables สองรายการนี้:

class R1 implements Runnable {
    public void run() {  }
    
}

class R2 implements Runnable {
    public void run() {  }
    
}

แล้วความแตกต่างระหว่างสิ่งนี้คืออะไร:

public static void main() {
    R1 r1 = new R1();
    R2 r2 = new R2();

    r1.run();
    r2.run();
}

และนี่:

public static void main() {
    R1 r1 = new R1();
    R2 r2 = new R2();
    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);

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

คำตอบ:


309

ตัวอย่างแรก:ไม่มีหลายเธรด ทั้งสองทำงานในเธรดเดียว (ที่มีอยู่) ไม่มีการสร้างเธรด

R1 r1 = new R1();
R2 r2 = new R2();

r1และr2เป็นเพียงวัตถุสองชนิดที่แตกต่างกันของคลาสที่ใช้Runnableอินเทอร์เฟซและใช้run()วิธีนี้ เมื่อคุณเรียกr1.run()คุณกำลังดำเนินการในเธรดปัจจุบัน

ตัวอย่างที่สอง:สองเธรดแยกกัน

Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);

t1และเป็นวัตถุของชั้นเรียนt2 Threadเมื่อคุณเรียกt1.start()ใช้เธรดจะเริ่มเธรดใหม่และเรียกrun()เมธอดของr1ภายในเพื่อเรียกใช้งานภายในเธรดใหม่นั้น


5
ฉันคิดว่าก่อนที่เราจะเรียกใช้ Thread # start () ไม่มีอะไรเกี่ยวข้องกับเธรด os จริง ๆ หรือไม่? มันเป็นเพียงวัตถุจาวา
Jaskey

4
ถูกต้องตามเอกสาร ตรวจสอบรหัสการเตรียมใช้งานวัตถุเธรดซึ่งสอดคล้องกับเอกสารประกอบ นอกจากนี้ในซอร์สโค้ดมันคือstart()ซึ่งเรียกเมธอด natvie ซึ่งจะต้องทำให้สิ่งต่าง ๆ ที่เกี่ยวข้องกับเธรด os เกิดขึ้น
Bhesh Gurung

3
เอกสารนวกรรมิกด้ายที่นี่ วัตถุกระทู้แหล่งที่มาเริ่มต้นเป็นที่นี่ start()แหล่งที่มาเป็นวิธีการที่นี่
Bhesh Gurung

92

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


2
ใน Hotspot JVM มีการแม็พโดยตรงระหว่างเธรด java และเธรดดั้งเดิม Thread.start()ภาวนาให้รัฐด้ายย้ายจากใหม่ของรัฐเพื่อRunnableรัฐ Runnable ไม่ได้หมายความว่าเธรดกำลังทำงานอยู่ เมื่อด้ายพื้นเมืองได้เริ่มต้นด้ายพื้นเมืองเรียกrun()วิธีการในหัวข้อ Java ซึ่งจะทำให้การเปลี่ยนสถานะจากด้ายRunnableที่จะเล่น เมื่อเธรดยกเลิกรีซอร์สทั้งหมดสำหรับทั้งเธรดเนทีฟและ Java ถูกปล่อย
แลกเปลี่ยนที่มากเกินไป

@overexchange ฉันสามารถค้นหาเนื้อหาเกี่ยวกับการเปลี่ยนสถานะได้ที่ไหน
twlkyao


35

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

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


21

Thread.start()สร้างเธรดใหม่จริงและมีสถานการณ์จำลองการดำเนินการของตนเอง

Thread.start()เรียกrun()เมธอดแบบอะซิงโครนัสซึ่งเปลี่ยนสถานะของเธรดใหม่เป็น Runnable

แต่Thread.run()ไม่ได้สร้างเธรดใหม่ใด ๆ แต่จะรันเมธอดการรันในเธรดที่กำลังรันในปัจจุบันแบบซิงโครนัส

หากคุณกำลังใช้งานอยู่Thread.run()คุณจะไม่ได้ใช้คุณสมบัติของการใช้เธรดหลายตัวเลย


8

การเรียกใช้run()กำลังเรียกใช้งานบนเธรดการโทรเช่นเดียวกับการเรียกใช้เมธอดอื่น ๆ ในขณะที่ Thread.start()สร้างหัวข้อใหม่ การเรียกใช้run()เป็นข้อผิดพลาดทางโปรแกรม


7

หากคุณrun()ใช้เมธอด main เธรดของเมธอด main จะเรียกใช้runเมธอดแทนเธรดที่คุณต้องการรัน

start()วิธีสร้างหัวข้อใหม่และซึ่งrun()วิธีการจะต้องมีการทำ


'วิธีการหลัก' ไม่มีส่วนเกี่ยวข้องกับมัน
มาร์ควิสแห่ง Lorne

3
@EJP โดยmainผู้เขียนหมายถึงวิธีการโทร คำตอบของเขาค่อนข้างดี +1 ;-)
dom_beau

1
@dom_beau ถ้านั่นคือสิ่งที่เขาหมายความว่าเขาควรจะพูดอย่างนั้น สิ่งที่เขาพูดไม่ถูกต้อง คำตอบนี้ไม่มีอะไร 'ค่อนข้างดี' มันเป็นเพียงความสับสน
มาร์ควิสแห่ง Lorne

5

t.start() เป็นวิธีการที่ไลบรารีจัดเตรียมให้โค้ดของคุณโทรเมื่อคุณต้องการเธรดใหม่

r.run()เป็นวิธีการที่คุณให้สำหรับห้องสมุดที่จะเรียกในหัวข้อใหม่


คำตอบเหล่านี้ส่วนใหญ่พลาดภาพใหญ่ซึ่งเป็นที่เกี่ยวกับภาษาจาวาไม่มีความแตกต่างระหว่างt.start()และr.run()มากกว่าระหว่างสองวิธีอื่น ๆ

พวกเขาทั้งสองเป็นเพียงวิธีการ พวกเขาทั้งสองทำงานในหัวข้อที่พวกเขาเรียกว่า พวกเขาทั้งสองทำสิ่งที่พวกเขาถูกเข้ารหัสให้ทำแล้วพวกเขาทั้งสองก็กลับไปยังผู้โทร

ความแตกต่างที่ใหญ่ที่สุดคือว่าส่วนใหญ่ของรหัสสำหรับt.start()เป็นพื้นเมืองรหัสในขณะที่ในกรณีส่วนใหญ่รหัสสำหรับr.run()เป็นไปได้ Java บริสุทธิ์ แต่นั่นไม่แตกต่างกันมาก รหัสคือรหัส รหัสภาษานั้นหายากกว่าและยากที่จะเข้าใจเมื่อคุณพบมัน แต่มันก็เป็นเพียงรหัสที่บอกคอมพิวเตอร์ว่าจะต้องทำอย่างไร

แล้วจะt.start()ทำอย่างไรดี?

มันสร้างเธรดดั้งเดิมใหม่จัดเรียงเธรดนั้นให้โทรt.run()แล้วมันบอกให้ระบบปฏิบัติการอนุญาตให้เธรดใหม่รัน จากนั้นมันจะกลับมา

แล้วจะr.run()ทำอย่างไร?

สิ่งที่ตลกคือคนที่ถามคำถามนี้เป็นคนที่เขียนมัน r.run()ทำทุกสิ่งที่คุณ (เช่นผู้พัฒนาที่เขียน) ออกแบบให้ทำ


4

Thread.start()รหัสลงทะเบียนเธรดด้วยตัวกำหนดตารางเวลาและตัวกำหนดตารางเวลาเรียกrun()เมธอด นอกจากนี้Threadคลาสในขณะที่Runnableเป็นอินเทอร์เฟซ


3

จุดที่สมาชิกทำไว้ถูกต้องแล้วฉันก็แค่อยากจะเพิ่มอะไรบางอย่าง สิ่งนี้คือ JAVA ไม่รองรับการสืบทอดหลายทาง แต่จะเป็นอย่างไรถ้าคุณต้องการได้คลาส B จากคลาส A อื่น แต่คุณสามารถได้มาจากคลาสหนึ่งเท่านั้น ปัญหาในตอนนี้คือวิธีการ "สืบทอด" จากทั้งสองคลาส: A และ Thread ดังนั้นคุณสามารถใช้ส่วนต่อประสานที่รันได้

public class ThreadTest{
   public void method(){
      Thread myThread = new Thread(new B());
      myThread.start;
   }
}

public class B extends A implements Runnable{...

คำอธิบายวิธีการ run () ด้วยความช่วยเหลือของตัวอย่างเกี่ยวกับ Runnable - ส่วนต่อประสานและ Thread - คลาส
Pinky Walve

1

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

หากคุณเรียกstart()ใช้เมธอดบนเธรด Java Virtual Machine จะเรียกใช้เมธอด run () และสองเธรดจะทำงานพร้อมกัน - เธรดปัจจุบัน ( main()ในตัวอย่างของคุณ) และเธรดอื่น ( รันได้)r1ในตัวอย่างของคุณ)

ดูstart()วิธีการซอร์สโค้ดในคลาส Thread

 /**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
    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();

ในโค้ดด้านบนคุณจะไม่เห็นrun()วิธีการเรียกใช้

private native void start0()เป็นผู้รับผิดชอบrun()วิธีการโทร JVM เรียกใช้งานเมธอดดั้งเดิมนี้


0

ในกรณีแรกคุณเพียงแค่เรียกใช้run()เมธอดr1และr2วัตถุ

ในกรณีที่สองคุณกำลังสร้างเธรดใหม่ 2 รายการ!

start()จะโทรหาrun()ในบางจุด!


7
ที่จริงแล้ว start () จะไม่เรียกใช้ run (): ถ้าเป็นเช่นนั้นเมธอด run () จะถูกดำเนินการโดยเธรดเดียวกันกับที่เรียกว่า start () สิ่งที่ start () จะทำคือสร้างเธรดซึ่งจะเรียกใช้เมธอด run ()
Bruno Reis

0

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

วิธีการเริ่มต้น: - ถูกกำหนดไว้ในระดับกระทู้ เมื่อเมธอดเริ่มต้นถูกเรียกใช้บนวัตถุเธรด 1-มันเรียกเมธอด native ภายใน (ไม่ใช่จาวา) ที่เรียกว่า start0 (); วิธี.

start0 (); เมธอด: รับผิดชอบการประมวลผลต่ำ (การสร้างสแต็กสำหรับเธรดและการจัดสรรเธรดในคิวตัวประมวลผล) ณ จุดนี้เรามีเธรดในสถานะพร้อม / รันได้

2-ในแต่ละครั้งที่เธรดตัวกำหนดเวลาตัดสินใจว่าเธรดเข้าสู่ตัวประมวลผลหลัก acorrding ถึง (ลำดับความสำคัญของเธรดรวมถึงอัลกอริทึมการกำหนดเวลา OS) เรียกใช้วิธีการเรียกใช้บนวัตถุ Runnable (ไม่ว่าจะเป็นวัตถุเธรด Runnable ปัจจุบันหรือ ไปที่ตัวสร้างเธรด) ที่นี่เธรดจะเข้าสู่สถานะกำลังทำงานและเริ่มดำเนินการงาน (วิธีการเรียกใช้)


-2

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

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

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


2
การเรียก `run () 'ไม่ใช่วิธีการสร้างโปรแกรมที่มีเธรด มีทางเดียวเท่านั้น
มาร์ควิสแห่ง Lorne

-2

เริ่มต้น () วิธีการเรียกใช้วิธีการแทนที่การเรียกใช้ของเธรดขยายระดับและอินเตอร์เฟซที่ดำเนินการ Runnable

แต่ด้วยการเรียกใช้ run () มันค้นหาวิธีการเรียกใช้ แต่ถ้าชั้นเรียนใช้อินเตอร์เฟซที่เรียกใช้ Runnable แล้วมันก็เรียกวิธีการแทนที่ () ของ Runnable

อดีต .:

`

public class Main1
{
A a=new A();
B b=new B();
a.run();//This call run() of Thread because run() of Thread only call when class 
        //implements with Runnable not when class extends Thread.
b.run();//This not run anything because no run method found in class B but it 
        //didn't show any error.

a.start();//this call run() of Thread
b.start();//this call run() of Thread
}

class A implements Runnable{
@Override
    public void run() {
            System.out.println("A ");
    }
}

class B extends Thread {

    @Override
    public void run() {
            System.out.println("B ");
    }
}

`

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