原文地址:extend
Thread 和 implements Runnable
作者:test
一個Thread的執行個體只能產生一個線程
or:
同一執行個體(Runnable執行個體)的多個線程
look:
public class Test { public static void main(String[] args) throws Exception{ MyThread mt = new MyThread(); mt.start(); mt.join(); Thread.sleep(3000); mt.start(); } } |
當線程對象mt運行完成後,我們讓主線程休息一下,然後我們再次在這個線程對象上啟動線程。結果我們看到:
Exception in thread "main" java.lang.IllegalThreadStateException
也就是這種線程對象一時運行一次完成後,它就再也不能運行第二次了。我們可以看一下它有具體實現:
public synchronized void start() { if (started) throw new IllegalThreadStateException(); started = true; group.add(this); start0(); } |
一個Thread的執行個體一旦調用start()方法,這個執行個體的started標記就標記為true,事實中不管這個線程後來有沒有執行到底,只要調用了一次start()就再也沒有機會運行了,這意味著:
[通過Thread執行個體的start(),一個Thread的執行個體只能產生一個線程]
那麼如果要在一個執行個體上產生多個線程(也就是我們常說的線程池),我們應該如何做呢?這就是Runnable介面給我們帶來的偉大的功能。
class R implements Runnable{ private int x = 0; public void run(){ for(int i=0;i<100;i++){ try{ Thread.sleep(10); }catch(Exception e){} System.out.println(x++); } } } |
正如它的名字一樣,Runnable的執行個體是可啟動並執行,但它自己並不能直接運行,它需要被Thread對象來封裝才行運行:
public class Test { public static void main(String[] args) throws Exception{ new Thread(new R()).start(); } } |
當然這個結果和mt.start()沒有什麼區別。但如果我們把一個Runnable執行個體給Thread對象多次封裝,我們就可以看到它們實際是在同一執行個體上啟動線程:
public class Test { public static void main(String[] args) throws Exception{ R r = new R(); for(int i=0;i<10;i++) new Thread(r).start(); } } |
x是執行個體對象,但結果是x被加到了999,說明這10個線程是在同一個r對象上啟動並執行。請大家注意,因為這個例子是在單CPU上啟動並執行,所以沒有對多個線程同時操作共同的對象進行同步。這裡是為了說明的方便而簡化了同步,而真正的環境中你無法預知程式會在什麼環境下運行,所以一定要考慮同步。
到這裡我們做一個完整的例子來說明線程產生的方式不同而產生的線程的區別:
package debug; import java.io.*; import java.lang.Thread; class MyThread extends Thread{ public int x = 0; public void run(){ System.out.println(++x); } }class R implements Runnable{ private int x = 0; public void run(){ System.out.println(++x); } } public class Test { public static void main(String[] args) throws Exception{ for(int i=0;i<10;i++){ Thread t = new MyThread(); t.start(); } Thread.sleep(10000);//讓上面的線程運行完成 R r = new R(); for(int i=0;i<10;i++){ Thread t = new Thread(r); t.start(); } } } |
上面10個線程對象產生的10個線程運行時列印了10次1。下面10個線程對象產生的10個線程運行時列印了1到10。我們把下面的10個線程稱為同一執行個體(Runnable執行個體)的多個線程。