首頁  >  問答  >  主體

java - 為什麼要將Runnable介面的子類別物件傳遞給Thread的建構子?

此外,runnable相比thread除了繼承方面,程式碼和資料獨立體現在哪裡?像是有些部落格寫的thread不能共享資源,runnable能分享資源,將thread中的變數改成static不就行了吧?就像下面這篇說的http://blog.csdn.net/uudou/ar...

巴扎黑巴扎黑2661 天前1514

全部回覆(3)我來回復

  • 漂亮男人

    漂亮男人2017-06-12 09:21:22

    跟數據似乎關係不大,我覺得Runnable有兩個好處:

    1. 實作Runnable以後,也就是可以開個執行緒跑(一般是用executorService.exec(command),挫一點也可以用new Thread(command).start()),也可以不開線程阻塞式的跑(直接呼叫command.run());

    2. Java 1.8以後可以用Lambda來跑,例如:

    new Thread(() -> {
        // Do something
    }).start();
    
    
    

    回覆
    0
  • 代言

    代言2017-06-12 09:21:22

    Runnable的好處是各種場景都可以用,例如你可以讓任何一個Class implements Runnable,但是extends Thread就有一些限制,因為Java單繼承的原因,在有些場景下沒用。

    回覆
    0
  • 天蓬老师

    天蓬老师2017-06-12 09:21:22

    回答:

    這個問題算是設計問題。

    之所以將 Thread 和 Runnable 分開,是希望把線程的 "創建過程" 與線程的 "執行邏輯" 徹底分開。

    也就是說:
    執行緒的創建過程是「程式碼」;
    執行緒的執行邏輯是「資料」;

    這聽起來有點叫人暈呼,不都是 JAVA 代碼麼?怎麼程式碼又變成資料了呢?

    我們不在這些概念上糾纏,我覺得可以倒轉過來思考這個問題,舉個例子來說明問題。

    討論過程:

    例如我要設計一個單執行緒程序,這個單執行緒需要完成兩個任務:

    1、印一句 hello world;
    2、計算一下 int a 與 int b 兩個數的和並輸出;

    注意:到底是執行 1? 還是 2?是由參數 n 決定的,n 是隨機數…

    為了讓這兩個任務在同一個執行緒執行,我們可以寫這樣的程式碼:

    float n = (float)Math.random();
    
    int a = 1;
    int b = 1;
    
    Thread t = new Thread() {
        @Override
        public void start() {
            if (n >= 0.5f) {
                System.out.println("hello world");
            } else {
                System.out.println(a + b);
            }
        }
    };
    
    t.start();
    

    上面的程式碼確實是可以完成任務的,但問題是我們把線程的 "創建過程" 和 "業務邏輯" 混淆在一起了…

    這樣不太妙。順便說一句,從作業系統層面來看,執行緒的創建過程其實是非常複雜的!

    Java 語言把這種複雜性都封裝得看不見了,雖然程式碼上就是一個 Thread 類,呼叫起來似乎也沒什麼門檻,但 Thread 的創建過程還是很複雜、很消耗資源的。

    言歸正傳,現在我再次加入一個小小的需求,除了前面的 1、2,我再加入一個 3,顯示一下系統當前時間戳。

    於是任務變成了:
    1、打印一句 hello world;
    2、計算一下 int a 與 int b 兩個數的和並輸出;
    3、顯示一下系統當前時間戳;

    注意,這時候我們需要修改 Thread 的創建過程,也就是修改 start 函數:

    float n = (float)Math.random();
    
    int a = 1;
    int b = 1;
    
    Thread t = new Thread() {
        @Override
        public void start() {
            if (n >= 0.33f) {
                System.out.println("hello world");
            } else if (n >= 0.66f) {
                System.out.println(a + b);
            } else {
                System.out.println(System.currentTimeMillis()); // 这里是新增的语句
            }
        }
    };
    
    t.start();
    

    討論至此,讓我們仔細觀察觀察…其實:

    Thread t = new Thread() {
        @Override
        public void start() {
            // ...
        }
    }
    

    這部分程式碼是不變的,只有 start 函數裡面的程式碼是隨著需求變化而修改的。

    那我們可不可以把這部分變化的內容包裝成一個介面? ?

    這應該是個不錯的主意!

    Thread t = new Thread() {
        private Runnable runnable; // 这里定义一个 Runnable 类型的成员
    
        @Override
        public void start() {
            if (null != this.runnable) {
                runnable.run(); // 在这里用接口来把频繁变化的业务逻辑从线程代码里给拿出去,只调用 run 函数
            }
        }
    }
    

    到這裡不知道你是否已經完全明白了? :D

    哈哈,Java 的 Thread 類別不是剛好提供了一個帶有 Runnable 參數的建構器麼?

    我們將業務程式碼被放到 Runnable 介面的實作類別裡:

    class BizLogicRun implements Runnable {
        @Override
        public void run() {
            float n = (float)Math.rand();
    
            int a = 1;
            int b = 1;
    
            if (n >= 0.33f) {
                System.out.println("hello world");
            } else if (n >= 0.66f) {
                System.out.println(a + b);
            } else {
                System.out.println(System.currentTimeMillis()); // 这里是新增的语句
            }
        }
    }
    

    那麼最後,我們可以這麼呼叫:

    Thread t = new Thread(new BizLogicRun());
    t.start();
    

    這樣就完成了線程的 "創建過程" 和 "業務邏輯" 徹底拆分!這種 "分割" 也為 Java 執行緒池(Thread Pool)技術做好了鋪墊。

    說實話,範例程式碼中的 Thread t = new Thread() { ... } 這個還是夠簡單的,但在執行緒池中建立 Thread 可就沒這麼簡單了。

    所以 "拆分" 是非常必要的!

    另外,我們是否可以想像:

    class PoolRun implements Runnable {
        List<Runnable> runnableList;
    }
    

    如果 Runable 實作類別裡面,夾帶的還是一個 Runnable 清單會怎麼樣呢?

    總結:

    1、使用Runnable 介面的目的是把線程的"創建過程" 與線程的"執行邏輯" 徹底分開;
    2、Thread 不能共享資源,Runnable 能共享資源,這個說法是不正確的;
    3、在討論過程中我們是從具體到抽象;
    4、我在例子中給出的程式碼確實比較簡單,但希望能說明白問題;

    好了,以上就是我對這個問題的回答,希望對你有幫助。

    回覆
    0
  • 取消回覆