【Java 併發編程】 01 多線程的實現

常用的實現多線程的2種方式:繼承 Thread 或者實現 Runanable 接口

Thread 類 實現了 Runnable 接口

public class Thread implements Runnable {}

//繼承 Thread 類

public class MyThread extends Thread {
    /*
       static Thread currentThread(),返回正在執行的線程對象的引用
       public static void sleep(long millis) 當前正在執行的線程以指定毫秒數暫定(暫時停止執行),毫秒結束後繼續執行

     */
    @Override
    public void run() {
        for (int i = 0; i <5 ; i++) {
            System.out.println(this.getName()+ "賣票"+i);
            //  使用Thread類中的方法 String getName(),可以返回線程的名稱。
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class MainThread {
    public static void main(String[] args){
        // 啓動3個線程t1,t2,t3;每個線程各循環5次!

        MyThread t1=new MyThread();
        MyThread t2=new MyThread();
        MyThread t3=new MyThread();
        t1.start();
        t2.start();
        t3.start();
    }

}

結果:
Thread-1賣票0
Thread-0賣票0
Thread-2賣票0
Thread-0賣票1
Thread-0賣票2
Thread-0賣票3
Thread-0賣票4
Thread-1賣票1
Thread-1賣票2
Thread-2賣票1
Thread-1賣票3
Thread-2賣票2
Thread-1賣票4
Thread-2賣票3
Thread-2賣票4

實現 Runnable 接口

Runnable接口中有一個抽象方法run
public interface Runnable { public abstract void run(); }

public class DemoRunnable implements  Runnable {
    @Override
    public void run() {
        for (int i = 0; i <5 ; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}



public class MIanRunnable {
    public static void main(String[] args){
        //實例化DemoRunnable 對象
        DemoRunnable r=new DemoRunnable();
        //創建線程對象
        Thread t0=new Thread(r,"0號窗口");
        Thread t1=new Thread(r,"1號窗口");
        Thread t2=new Thread(r,"2號窗口");
        t0.start();
        t1.start();
        t2.start();

    }
}

結果:
1號窗口0
1號窗口1
2號窗口0
0號窗口0
0號窗口1
0號窗口2
0號窗口3
0號窗口4
2號窗口1
2號窗口2
2號窗口3
2號窗口4
1號窗口2
1號窗口3
1號窗口4

Thread 中的 start() 方法分析

是不是用一種疑問,邏輯業務在 run 方法中,爲什麼開啓線程 要用start() 方法呢?

start() 源碼如下所示:

public synchronized void start() {
    if (threadStatus != 0)
        throw new IllegalThreadStateException();
    group.add(this);

    boolean started = false;
    try {
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
        }
    }
}
  • 檢查線程的狀態,是否可以啓動;
  • 把線程加入到線程group中;
  • 調用了start0()方法。

Start方法中最終調用的是start0方法,並不是run方法,我們查看 start0() 方法,start0是一個native方法,也稱爲JNI(Java Native Interface)方法。JNI方法是java和其它語言交互的方式。同樣也是java代碼和虛擬機交互的方式,虛擬機就是由C++和彙編所編寫。(一句話概括 ,native 修飾的方法 實在JVM 中的實現的,也就是說 start0() 方法 jvm 中,JVM 運行的 run() ) 👉 線程的生命週期
在這裏插入圖片描述

*the Java Virtual Machine calls the run method of this thread。
java虛擬機調用這個線程的run方法。*

private native void start0();

我們看一下run 方法,發現有一個target ,target 又是什麼呢?

@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

查看 Thread 的構造函數,返現target 是一個Runnable的實現對象,

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

查看Thread 中 初始化方法,

private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc,
                  boolean inheritThreadLocals){
   // target 爲成員變量
  this.target = target;
}

在這裏插入圖片描述

Thread 和 Ruannable 區別

Thread,是一個類,實現是 Ruannable 接口。Ruannable 是一個接口。所以繼承thread類實現多線程,其實也相當於是實現runnable接口的run方法。

java 是單繼承語言,一個類只能有一個父類,但是可以實現多個接口,Ruannable的擴展性更加好一些,避免了java中單繼承的侷限性。

多個線程基於某一個Runnable對象建立的,共享Runnable對象資源,增加程序的健壯性,實現瞭解耦操作,代碼和線程獨立。

繼承 Thread 類, run 方法實現在 Thread 子類中,thread 對象運行自己的 run 方法邏輯,創建對象以及業務邏輯沒有分離,實現Runnable 接口,run方法邏輯轉移到 Runnable 的實現類中,是調用 Runnable 實現的 run 方法邏輯,可以將創建對象和執行邏輯業務分離開來,線程控制邏輯在Thread類中,業務運行邏輯在Runnable實現類中。解耦更爲徹底
在這裏插入圖片描述

通過以上比較,推薦使用 Ruannable 接口 實現多線程 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章