Sự khác biệt giữa Thread start () và Runnable run ()


224

Nói rằng chúng tôi có hai Runnables này:

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

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

Vậy thì sự khác biệt giữa cái này là gì:

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

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

Và điều này:

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();
}

Câu trả lời:


309

Ví dụ đầu tiên: Không có nhiều chủ đề. Cả hai thực hiện trong luồng đơn (hiện có). Không tạo chủ đề.

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

r1r2chỉ là hai đối tượng khác nhau của các lớp thực hiện Runnablegiao diện và do đó thực hiện run()phương thức. Khi bạn gọi r1.run()bạn đang thực hiện nó trong luồng hiện tại.

Ví dụ thứ hai: Hai luồng riêng biệt.

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

t1t2là đối tượng của lớp Thread. Khi bạn gọi t1.start(), nó bắt đầu một luồng mới và gọi run()phương thức r1bên trong để thực thi nó trong luồng mới đó.


5
Couuld Tôi xem xét rằng trước khi chúng ta gọi Thread # start (), không có gì thực sự liên quan đến chủ đề os xảy ra? Nó chỉ là một đối tượng java.
Jaskey

4
Điều đó đúng theo tài liệu. Kiểm tra mã khởi tạo đối tượng luồng, phù hợp với tài liệu. Cũng trong mã nguồn, đó là start(), đang gọi một phương thức natvie, điều này phải làm cho các vấn đề liên quan đến luồng os xảy ra.
Bhesh Gurung

3
Tài liệu xây dựng chủ đề là ở đây . Chủ đề khởi tạo nguồn ở đây . start()nguồn phương pháp là đây .
Bhesh Gurung

92

Nếu bạn chỉ gọi run()trực tiếp, nó được thực hiện trên luồng gọi, giống như bất kỳ cuộc gọi phương thức nào khác. Thread.start()được yêu cầu thực sự tạo ra một luồng mới để runphương thức của runnable được thực thi song song.


2
Trong Hotspot JVM, có một ánh xạ trực tiếp giữa luồng java và luồng gốc. Thread.start()việc gọi làm cho trạng thái luồng chuyển từ trạng thái mới sang trạng thái Runnable . Runnable không có nghĩa là chủ đề đang chạy. Khi luồng gốc đã được khởi tạo, luồng gốc sẽ gọi run()phương thức trong luồng Java, điều này làm cho trạng thái luồng thay đổi từ Runnable sang Running . Khi luồng kết thúc, tất cả các tài nguyên cho cả luồng gốc và luồng Java đều được giải phóng.
trao đổi quá mức

@overexchange Tôi có thể tìm tài liệu về thay đổi trạng thái ở đâu.
twlkyao

73

Sự khác biệt là Thread.start()bắt đầu một luồng gọi run()phương thức, trong khi Runnable.run()chỉ gọi run()phương thức trên luồng hiện tại.


35

Sự khác biệt là khi chương trình gọi start()phương thức, một luồng mới được tạo và mã bên trong run()được thực thi trong luồng mới trong khi nếu bạn gọi run()phương thức trực tiếp thì luồng mới sẽ được tạo và mã bên trong run()sẽ thực thi trực tiếp trong luồng hiện tại.

Một điểm khác biệt giữa start()run()trong luồng Java là bạn không thể gọi start()hai lần. Sau khi bắt đầu, start()cuộc gọi thứ hai sẽ chuyển IllegalStateExceptionsang Java trong khi bạn có thể gọi run()phương thức nhiều lần vì đây chỉ là một phương thức thông thường .


21

Thực tế Thread.start()tạo ra một chủ đề mới và có kịch bản thực hiện riêng của nó.

Thread.start()gọi run()phương thức không đồng bộ, thay đổi trạng thái của Thread mới thành Runnable.

Nhưng Thread.run()không tạo ra bất kỳ chủ đề mới. Thay vào đó, nó thực thi phương thức chạy trong luồng chạy hiện tại một cách đồng bộ.

Nếu bạn đang sử dụng Thread.run()thì bạn hoàn toàn không sử dụng các tính năng của đa luồng.


8

invoke run()đang thực thi trên luồng gọi, giống như bất kỳ lệnh gọi phương thức nào khác. trong khi Thread.start()tạo ra một chủ đề mới. Gọi run()là một lỗi lập trình.


7

Nếu bạn làm run()trong phương thức chính, luồng của phương thức chính sẽ gọirun phương thức thay vì luồng bạn yêu cầu chạy.

Các start()phương pháp tạo chủ đề mới và mà run()phương pháp đã được thực hiện


"Phương pháp chính" không có gì để làm với nó.
Hầu tước Lorne

3
@EJP, bởi mainngười viết có nghĩa là phương thức gọi. Câu trả lời của anh ấy khá tốt. +1 ;-)
dom_beau

1
@dom_beau Nếu đó là những gì anh ấy có nghĩa là anh ấy nên nói như vậy. Những gì anh ấy đã nói là không chính xác. Không có gì "khá tốt" về câu trả lời này. Nó chỉ là một mớ hỗn độn.
Hầu tước Lorne

5

t.start() là phương thức mà thư viện cung cấp cho mã của bạn để gọi khi bạn muốn một luồng mới.

r.run()là phương thức mà bạn cung cấp cho thư viện để gọi trong luồng mới.


Hầu hết các câu trả lời này đều bỏ lỡ bức tranh lớn, đó là, theo như ngôn ngữ Java có liên quan, không có sự khác biệt giữa t.start()r.run() hơn là giữa hai phương thức khác.

Cả hai chỉ là phương pháp. Cả hai đều chạy trong chuỗi gọi chúng . Cả hai đều làm bất cứ điều gì họ được mã hóa để làm, và sau đó cả hai trở về, vẫn trong cùng một chủ đề, với người gọi của họ.

Sự khác biệt lớn nhất là hầu hết các mã cho t.start()là mã gốc trong khi, trong hầu hết các trường hợp, mã chor.run() sẽ là tinh khiết Java. Nhưng đó không phải là nhiều sự khác biệt. Mã là mã. Mã gốc khó tìm hơn và khó hiểu hơn khi bạn tìm thấy nó, nhưng nó vẫn chỉ là mã cho máy tính biết phải làm gì.

Vậy, cái gì t.start() làm gì?

Nó tạo ra một chủ đề mới, nó sắp xếp để chủ đề đó gọi t.run() và sau đó nó báo cho HĐH để cho luồng mới chạy. Rồi nó trở về.

Và cái gì r.run() làm gì?

Điều buồn cười là, người hỏi câu hỏi này là người đã viết nó . r.run()làm bất cứ điều gì bạn (tức là, nhà phát triển đã viết nó) đã thiết kế nó để làm.


4

Thread.start()mã đăng ký Thread với bộ lập lịch và bộ lập lịch gọi run()phương thức. Ngoài ra, Threadlà lớp trong khi Runnablelà một giao diện.


3

Các điểm, mà các thành viên đã làm đều ổn nên tôi chỉ muốn thêm một cái gì đó. Có điều là JAVA không hỗ trợ Đa kế thừa. Nhưng nếu bạn muốn lấy một lớp B từ một lớp A khác, nhưng bạn chỉ có thể xuất phát từ một Lớp. Vấn đề bây giờ là làm thế nào để "lấy được" từ cả hai lớp: A và Thread. Do đó, bạn có thể sử dụng Giao diện Runnable.

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

public class B extends A implements Runnable{...

giải thích độc đáo về phương thức run () với sự trợ giúp của một ví dụ về Runnable - giao diện và Thread - một lớp
Pinky Walve

1

Nếu bạn trực tiếp gọi run()phương thức, bạn không sử dụng tính năng đa luồng vì run()phương thức được thực thi như một phần của luồng người gọi.

Nếu bạn gọi start()phương thức trên Thread, Máy ảo Java sẽ gọi phương thức run () và hai luồng sẽ chạy đồng thời - Chủ đề hiện tại ( main()trong ví dụ của bạn) và Chủ đề khác (Runnabler1 trong ví dụ của bạn).

Hãy xem mã nguồn của start()phương thức trong lớp 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();

Trong đoạn mã trên, bạn không thể thấy lời gọi đến run()phương thức.

private native void start0()chịu trách nhiệm gọi run()phương thức JVM thực thi phương thức riêng này.


0

Trong trường hợp đầu tiên, bạn chỉ cần gọi run()phương thức của r1r2 đối tượng .

Trong trường hợp thứ hai, bạn thực sự đang tạo 2 Chủ đề mới!

start()sẽ gọi run()vào một lúc nào đó!


7
Trên thực tế, start () sẽ không gọi run (): nếu có, thì phương thức run () sẽ được thực thi bởi cùng một luồng được gọi là start (). Những gì start () sẽ làm là tạo ra một luồng sẽ gọi phương thức run ().
Bruno Reis

0

phương thức chạy: - là một phương thức trừu tượng ban đầu được tạo trong giao diện Runnable và được ghi đè trong lớp Thread cũng như các lớp con Thread (Như Thread triển khai Runnable trong mã nguồn của nó) và bất kỳ lớp triển khai nào khác của giao diện Runnable. - Nó được sử dụng để tải luồng (đối tượng có thể chạy) với tác vụ mà nó dự định thực hiện do đó bạn ghi đè lên nó để viết tác vụ đó.

phương thức start: - được định nghĩa trong lớp Thread. Khi phương thức start được gọi trên một đối tượng Thread 1- nó gọi phương thức bên trong (nonjava) được gọi là start0 (); phương pháp.

bắt đầu0 (); Phương thức: chịu trách nhiệm xử lý thấp (tạo ngăn xếp cho một luồng và phân bổ luồng trong hàng đợi bộ xử lý) tại thời điểm này, chúng ta có một luồng ở trạng thái Sẵn sàng / Chạy được.

2- Tại thời điểm Bộ lập lịch xử lý quyết định rằng một luồng đi vào lõi xử lý lấy từ (ưu tiên luồng cũng như thuật toán lập lịch hệ điều hành) được gọi trên đối tượng Runnable (cho dù đó là đối tượng luồng Runnable hiện tại hay đối tượng Runnable được truyền đến hàm tạo của luồng) ở đây một luồng vào trạng thái Chạy và bắt đầu thực thi tác vụ của nó (phương thức chạy)


-2

Các phương thức start () và run () riêng biệt trong lớp Thread cung cấp hai cách để tạo các chương trình luồng. Phương thức start () bắt đầu thực thi luồng mới và gọi phương thức run (). Phương thức start () trả về ngay lập tức và luồng mới thường tiếp tục cho đến khi phương thức run () trả về.

Phương thức run () của lớp Thread không làm gì cả, vì vậy các lớp con nên ghi đè phương thức bằng mã để thực thi trong luồng thứ hai. Nếu một Chủ đề được khởi tạo với một đối số Runnable, thì phương thức run () của luồng thực thi phương thức run () của đối tượng Runnable trong luồng mới thay thế.

Tùy thuộc vào bản chất của chương trình luồng của bạn, việc gọi trực tiếp phương thức Thread run () có thể cho cùng một đầu ra như gọi qua phương thức start (), nhưng trong trường hợp sau, mã thực sự được thực thi trong một luồng mới.


2
Gọi `run () 'không phải là cách để tạo các chương trình luồng. Chỉ co một cach duy nhât.
Hầu tước Lorne

-2

Phương thức bắt đầu cuộc gọi phương thức Start () của lớp mở rộng Thread và giao diện thực hiện Runnable.

Nhưng bằng cách gọi run () nó tìm kiếm phương thức run nhưng nếu lớp thực hiện giao diện Runnable thì nó gọi phương thức ghi đè run () của Runnable.

Ví dụ.:

`

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 ");
    }
}

`

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.