Java并发基础01. 传统线程技术中创建线程的两种方式
傳統的線程技術中有兩種創建線程的方式:一是繼承Thread類,并重寫run()方法;二是實現Runnable接口,覆蓋接口中的run()方法,并把Runnable接口的實現扔給Thread。這兩種方式大部分人可能都知道,但是為什么這樣玩就可以呢?下面我們來詳細分析一下這兩種方法的來龍去脈。
1. 揭秘Thread中run() |
上面我們看到這兩種方式都跟run()方法有關,所以我們來看一下Thread的源碼中run()方法到底都干了什么: @Override public void run() {if (target != null) {target.run();} }
我們可以看出,run()方法中很簡單,只有一個if語句,如果target不為空就執行target的run()方法,否則什么也不干,那么這target到底是何方神圣呢?我們點擊進去可以看到:
private Runnable target;原來target就是Runnable接口,我們再點進Runnable看看:
@FunctionalInterface public interface Runnable {public abstract void run(); }Runnable中就一個方法,也是run()方法!好了,現在再回到Thread類的run()方法中,如果target不為空,即實現了Runnable接口,也即實現了Runnable中的run()方法,那么我們就使用該接口中的run()方法;如果target為空,即沒有實現Runnable接口,那我們什么也不做,即線程創建后立馬就消失了。
所以到這里,大家就明白了為什么創建線程有上面兩種方式了。第一種:你不是要先進行if判斷么?我現在不判斷了,我把你的if干掉,我在run()方法中自己寫代碼,想干啥就干啥,即重寫Thread中的run()方法,;第二種:你不是要先進行if判斷么?行,給你一個Runnable接口讓你判斷,但你還是得調用我Runnable中的run()方法啊,那我重寫我Runnable中的run()方法不就行了!
知道了來龍去脈后,下面就針對這兩種傳統的方式寫個實例。
2. 創建方式1:繼承Thread類 |
只要兩步即可創建并開啟一個線程:
- 繼承Thread類,并實現run()方法;
- 調用start()方法開啟線程。
由于只要實現一個run()方法即可,所以我們可以使用java中的匿名內部類來實現,如下:
public class TraditionalThread {public static void main(String[] args) {/********** 第一種方法:繼承Thread類,覆寫run()方法 **************/Thread thread1 = new Thread(){@Overridepublic void run() {try {Thread.sleep(500);//讓線程休息500毫秒} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName());//打印出當前線程名}};thread1.start();//開啟線程} }3. 創建方式2:實現Runnable接口 |
只要兩步即可創建并開啟一個線程:
- 實現Runnable接口,并實現run()方法;
- 調用start()方法開啟線程。
由于只要實現一個run()方法即可,所以我們也可以使用java中的匿名內部類來實現,如下:
public class TraditionalThread {public static void main(String[] args) {/********** 第二種方法:實現Runnable接口,扔給Thread **************/Thread thread2 = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName());}});thread2.start();} }4. 兩種方式同時使用 |
如果有個哥們比較給力,他兩種方式同時使用了,即:既實現了Thread類中的run()方法,又給Thread扔了一個實現了run()方法的Runnable。如下所示:
public class TraditionalThread {public static void main(String[] args) {//這哥們的代碼寫的比較給力new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Runnable:" + Thread.currentThread().getName());}}){@Overridepublic void run() {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread:" + Thread.currentThread().getName());}}.start();}}現在又會執行哪個呢?我們運行一下上面的程序就會發現,它會打印出Thread的信息,所以運行的是Thread的run()方法,知道結論了,但是為啥呢?
從面向對象的思想去考慮:上面一段代碼其實是新new了一個對象(子對象)繼承了Thread對象(父對象),在子對象里重寫了父類的run()方法,父對象中扔了個Runnable進去,父對象中的run()方法就是最初的帶有if判斷的run()方法。
好了,現在執行start()后,肯定先在子類中找run()方法,找到了,父類的run()方法自然就被干掉了,所以會打印出Thread:,如果我們現在假設子類中沒有重寫run()方法,那么必然要去父類找run()方法,父類的run()方法中就得判斷是否有Runnable傳進來,現在有一個,所以執行Runnable中的run()方法,那么就會打印Runnable:出來。
OK,傳統的創建線程的兩種方式就總結這么多~如有錯誤之處,歡迎留言指正~
轉載于:https://www.cnblogs.com/eson15/p/9822870.html
總結
以上是生活随笔為你收集整理的Java并发基础01. 传统线程技术中创建线程的两种方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Solr安装步骤 + dataimpor
- 下一篇: Java并发编程——volatile