2011-12-20 24 views
162

Giả sử chúng ta có hai Runnables này:là gì sự khác biệt giữa Chủ đề start() và chạy Runnable()

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

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

Và điều này::

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

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

Sau đó, sự khác biệt giữa điều này là những gì

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

Trả lời

242

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

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

r1r2 chỉ là hai đối tượng khác nhau của các tầng lớp mà thực hiện giao diện Runnable và do đó thực hiện phương pháp run(). Khi bạn gọi r1.run() bạn đang thực hiện nó trong chuỗi hiện tại.

ví dụ thứ hai: Hai chủ đề riêng biệt.

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

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

+3

Couuld Tôi cho rằng trước khi chúng ta gọi là chủ đề # start(), không có gì thực sự so với os chủ đề sẽ xảy ra? Nó chỉ là một đối tượng java. – Jaskey

+3

Đúng theo tài liệu. Kiểm tra mã khởi tạo đối tượng thread, phù hợp với tài liệu. Cũng trong mã nguồn, nó là 'start()', gọi là phương thức natvie, cái mà phải làm cho những thứ liên quan đến chuỗi os xảy ra. –

+2

Tài liệu xây dựng của chủ đề là [ở đây] (https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#Thread (java.lang.ThreadGroup,% 20java.lang.Runnable, % 20java.lang.String)). Nguồn khởi tạo đối tượng chủ đề là [tại đây] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Thread.java#Thread.init% 28java.lang.ThreadGroup% 2Cjava.lang.Runnable% 2Cjava.lang.String% 2Clong% 29). nguồn phương thức 'start()' là [ở đây] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Thread.java#Thread .start% 28% 29). –

66

Nếu bạn chỉ cần gọi run() trực tiếp, nó thực hiện trên các thread kêu gọi, cũng giống như bất kỳ cuộc gọi phương pháp khác. Thread.start() là bắt buộc để thực sự tạo một chuỗi mới để phương thức run của ứng dụng chạy được thực hiện song song.

+2

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

+0

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

0

Trong trường hợp đầu tiên bạn chỉ cần gọi hàm run() của đối tượng r2 adn r2.

Trong trường hợp thứ hai, bạn đang thực sự tạo 2 Chủ đề mới! ;) start() sẽ gọi run() tại một số điểm!

+5

Trên thực tế, start() sẽ không gọi run(): nếu nó đã làm, thì phương thức run() sẽ được thực hiện bởi cùng một luồng được gọi là start(). Điều start() sẽ làm là tạo một luồng sẽ gọi phương thức run(). –

3

Thread.start() mã đăng ký Chủ đề có lập lịch và trình lên lịch gọi phương thức run(). Ngoài ra, Thread là lớp trong khi Runnable là một giao diện.

17

Thực ra, Thread.start() tạo chuỗi mới và có kịch bản thực thi riêng.

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

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

Nếu bạn đang sử dụng Thread.run() sau đó bạn không sử dụng các tính năng của đa luồng cả.

6

Nếu bạn làm run() trong phương pháp chính, chuỗi của phương thức chính sẽ gọi phương thức run thay vì chuỗi bạn yêu cầu để chạy.

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

+0

'Phương pháp chính' không liên quan gì đến nó. – EJP

+3

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

+0

Điều này phải được đánh dấu là câu trả lời được chấp nhận. –

39

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

+14

Tại sao một người dùng 80k đưa ra câu trả lời như thế này hai năm sau khi các câu trả lời tốt hơn đã được đưa ra và được chấp nhận? – Sebastian

+16

@Sebastian Tôi không chấp nhận giả thuyết của bạn. Cụ thể, câu trả lời được chấp nhận là chi tiết và chất lượng kém, và tôi không thấy bất kỳ câu trả lời nào khác thể hiện tốt hơn câu trả lời này. – EJP

7

gọi run() đang thực hiện trên chuỗi cuộc gọi, giống như bất kỳ cuộc gọi phương thức nào khác. trong khi Thread.start() tạo một chuỗi mới. gọi run() là lỗi có lập trình.

3

Những điểm mà các thành viên tạo ra đều ổn, vì vậy tôi chỉ muốn thêm thứ gì đó. Vấn đề là JAVA không hỗ trợ Multi-inheritance. Nhưng Điều gì sẽ xảy ra nếu bạn muốn lấy được một lớp B 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{... 
+0

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 - một giao diện và Thread - một lớp –

-1

Phương thức start() và run() riêng biệt trong lớp Thread cung cấp hai cách để tạo chương trình luồng. Phương thức start() bắt đầu thực hiện 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 hiện trong chuỗi thứ hai. Nếu một Thread được khởi tạo với một đối số Runnable, phương thức run() của thread thực thi phương thức run() của đối tượng Runnable trong chủ đề 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, gọi phương thức Thread run() trực tiếp có thể cho đầu ra tương tự như gọi qua phương thức start(), nhưng trong trường hợp sau, mã thực sự được thực hiện trong một chuỗi mới.

+0

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. – EJP

0

Giả sử bạn là Người quản lý của khách sạn có tên là Chủ đề. Vì vậy, về cơ bản những gì t1.run() làm là nó làm cho bạn phải làm tất cả các nhiệm vụ chính mình, trong khi người trợ giúp Chủ đề khác của bạn ngồi nhàn rỗi twiddling ngón tay cái của họ. Nhưng nếu bạn sử dụng t1.start(), một trong những người giúp đỡ của bạn được chỉ định một số nhiệm vụ và sau đó anh ta/cô ấy bắt đầu thực hiện nhiệm vụ đó, trong khi bạn thực hiện công việc bạn phải làm là quản lý những người trợ giúp.

Nguồn: Programming Interview: Threads in Operating System (Java) Part 2 Multithreading

+1

OMG. YouTube không phải là một tham chiếu quy phạm. 'Một khách sạn tên là Chủ đề' và 'những người giúp việc khác' chỉ thêm vào sự nhầm lẫn. Các chủ đề khách sạn, hay người giúp đỡ? Đây chỉ là vô nghĩa. – EJP

2

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

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

Sự khác biệt lớn nhất là hầu hết mã cho t.start()mã gốc trong khi, trong hầu hết các trường hợp, mã cho r.run() sẽ là Java thuần túy. Nhưng đó không phải là một 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ì vậy, t.start() làm gì?

Nó tạo ra một chuỗi gốc mới, nó sắp xếp cho chuỗi đó để gọi t.run(), và sau đó nó cho hệ điều hành để cho thread mới chạy. Sau đó, nó trả về.

r.run() làm gì?

Điều thú vị là, người hỏi câu hỏi này là người đã viết nó. r.run() thực hiện bất kỳ điều gì bạn (tức là, nhà phát triển đã viết nó) đã thiết kế để thực hiện.


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

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

+0

Nếu 'hầu hết mã cho 't.run()' là mã gốc', thì làm cách nào 'chính xác bất kỳ điều gì bạn (nghĩa là nhà phát triển đã viết nó) đã thiết kế nó để làm'? Bạn có nghĩa là hầu hết các mã cho 'Thread.start()' là mã nguồn gốc? – EJP

+0

@EJP, Rất tiếc! Cảm ơn vì đã bắt được điều đó. –

25

khác biệt chính là khi chương trình gọi start() phương pháp một mới Chủ đề được tạo ra và mã bên run() phương pháp được thực hiện trong đề tài mới trong khi nếu bạn gọi run() phương pháp trực tiếp không Chủ đề mới được tạo ra và mã bên trong chạy() sẽ thực hiện trên Chủ đề hiện tại.

Một khác biệt giữa bắt đầu và chạy trong chuỗi Java là bạn không thể gọi phương thức start() hai lần trên đối tượng chuỗi. khi bắt đầu, lệnh gọi thứ hai của start() sẽ ném IllegalStateException trong Java trong khi bạn có thể gọi phương thức run() hai lần.

2

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

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

Hãy nhìn vào mã nguồn của start() phương pháp trong Thread class

/** 
    * 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ể nhìn thấy gọi đến run() phương pháp.

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

0

Phương thức ghi đè chạy cuộc gọi phương thức Start() của lớp mở rộng Thread và giao diện Runnable thực hiện.

Nhưng bằng cách gọi hàm run() nó tìm kiếm phương thức chạy nhưng nếu lớp triển khai giao diện Runnable thì nó gọi phương thức run() ghi đè 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 "); 
    } 
} 

'

Các vấn đề liên quan