深入理解多線程(一)
1.多線程的原理
1.1 代碼展示多線程
為了演示多線程,我們用一個代碼來展示多線程的效果:
public class App {
public static void main(String[] args) throws InterruptedException {
//子線程
new Thread(() -> {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+":小強");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//主線程
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+":旺財");
Thread.sleep(100);
}
}
}
流程圖:

程序啟動運行main時候,java虛擬機啟動一個進程,主線程main在main()調用時候被創建。隨着調用Thread的對象的start方法,另外一個新的線程也啟動了,這樣,整個應用就在多線程下運行。 通過這張圖我們可以很清晰的看到多線程的執行流程。
1.2 圖解多線程時內存狀態圖
多線程執行時,在棧內存中,其實每一個執行線程都有一片自己所屬的棧內存空間。進行方法的壓棧和彈棧。

jvm虛擬機中,堆中放的是對象和數據,棧中放的是方法,方法區中放的是class類文件
2. 創建線程的兩種方法
2.1 繼承Thread類
public class MyThread extends Thread{
public MyThread(String name){
super(name);
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("小強");
}
}
}
//調用
new MyThread("myThread").start
2.2 實現Runable接口
public class MyThread implements Runnable{
@Override
public void run() {
System.out.println("myThread");
}
}
//調用
Thread thread=new Thread(new MyThread());
thread.start()
我們更傾向於使用匿名內部類:
new Thread(() -> {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+":小強");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
通過實現Runnable接口,使得該類有了多線程類的特征。run()方法是多線程程序的一個執行目標。所有的多線程
代碼都在run方法里面。Thread類實際上也是實現了Runnable接口的類。
在啟動多線程的時候,需要先通過Thread類的構造方法Thread(Runnable target) 構造出對象,然后調用Thread 對象的start()方法來運行多線程代碼。
實際上所有的多線程代碼都是通過運行Thread的start()方法來運行的。因此,不管是繼承Thread類還是實現
Runnable接口來實現多線程,最終還是通過Thread的對象的API來控制線程的
2.3 兩者的優劣
如果一個類繼承Thread,則不適合資源共享。但是如果實現了Runable接口的話,則很容易的實現資源共享。
總結:
實現Runnable接口比繼承Thread類所具有的優勢:
- 適合多個相同的程序代碼的線程去共享同一個資源。
- 可以避免java中的單繼承的局限性。
- 增加程序的健壯性,實現解耦操作,代碼可以被多個線程共享,代碼和線程獨立。
- 線程池只能放入實現Runable或Callable類線程,不能直接放入繼承Thread的類。
擴充:在java中,每次程序運行至少啟動2個線程。一個是main線程,一個是垃圾收集線程。因為每當使用
java命令執行一個類的時候,實際上都會啟動一個JVM,每一個JVM其實在就是在操作系統中啟動了一個進
程。
