前言
小鹹兒要開始向多線程的領域進軍了,第一件事當然是先來了解一下它的背景,這樣才能夠宏觀把控,立於不敗之地。首先先來學習幾個概念:
敘述
寶圖
線程與進程
進程:就是獨立的一個應用程序,在進程中,會有N多個線程。例如一列火車
線程:一條執行路徑。例如每一節火車車廂
多線程:所有線程的集合。例如多節火車車廂
多線程的目的: 提高程序效率,而不能提高下載速度。
同步與異步
同步:代碼自上至下順序執行
異步:新的執行路徑,不會影響其他的線程
五種狀態
這裏的五種狀態,指的是線程的五種狀態:新建、就緒、運行、阻塞、死亡
那麼這五種狀態是如何轉化的呢?
守護線程與非守護線程
守護線程:也被成爲後臺線程,即和main相關的線程,其中典型代表JVM的垃圾回收線程
非守護線程:用戶線程屬於非守護線程,即用戶創建的線程,如果主線程停止掉,不會影響用戶。如果將非守護線程設置爲守護線程,也十分的簡單,調用Thread對象的setDaemon(true)方法即可。
new Thread.setDaemon(true)
創建線程的四種方式
繼承Thread類,並重寫run()方法
package com.practice.demo.thread;
/**
* 線程的第一個實例,繼承Thread類
* @author Phyllis
* @date 2019年6月30日15:08:26
*/
public class FirstThread extends Thread{
private int i;
/**
* 重寫run()方法,run()方法的方法體就是線程執行體
*/
@Override
public void run(){
for (; i<100 ;i++){
// 當線程類繼承Thread類時,直接使用this即可
System.out.println(getName()+" "+i);
}
}
public static void main(String[] args){
for (int i=0; i<100; i++){
// 調用Thread的currentThread()方法獲取當前線程
System.out.println(Thread.currentThread().getName()+" "+i);
if (i == 20){
// 創建並啓動第一個線程
new FirstThread().start();
// 創建並啓動第二個線程
new FirstThread().start();
}
}
}
}
實現Runnable接口,並重寫run()方法
package com.practice.demo.thread;
/**
* 線程的第二個實例,實現Runnable接口
* @author Phyllis
* @date 2019年7月2日17:26:05
*/
public class SecondThread implements Runnable{
private int i;
/**
* run()方法同樣是線程執行體
*/
@Override
public void run() {
for (; i < 100; i++){
// 當線程類實現Runnable接口時
// 如果想獲取當前線程,只能用Thread.currentThread()方法
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
public static void main(String[] args){
for (int i = 0; i<100; i++){
System.out.println(Thread.currentThread().getName()+" "+i);
if (i == 20){
SecondThread st = new SecondThread();
// 通過new Thead(target,name)方法創建新線程
new Thread(st, "新線程1").start();
new Thread(st,"新線程2").start();
}
}
}
}
匿名內部類
public class Thread003 {
public static void main(String[] args) {
System.out.println("main... 主線程開始...");
Thread t1 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(" 子 i:" + i);
}
}
});
t1.start();
for (int i = 0; i < 10; i++) {
System.out.println("main..i:" + i);
}
System.out.println("main... 主線程結束...");
}
}
使用Callable和Future創建線程
package com.practice.demo.thread;
/**
* 線程的第三個實例,使用Callable和Future創建線程
* @author Phyllis
* @date 2019年7月2日17:26:05
*/
public class ThirdThread implements Runnable{
public static void main(String[] args){
// 創建Callable對象
ThirdThread rt = new ThirdThred();
// 先試用Lambda表達式創建Callable<Integer>對象
// 使用FutureTask來包裝Callable對象
FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)()->{
int i = 0;
for(; i < 100; i++){
System.out.println(Thread.currentThread().getName() + " 的循環變量i的值:" + i);
}
return i;
});
for (int i = 0; i < 100; i++){
System.out.println(Thread.currentThread().getName() + " 的循環變量i的值:" + i);
if(i == 20){
// 實質上還是以Callable對象來創建和啓動線程的
new Thread(task, "有返回值的線程").start();
}
}
try{
// 獲取線程返回值
System.out.println("子線程的返回值:" + task.get());
}
catch (Exception ex){
ex.printStackTrace();
}
}
}
比較
採用實現Runnable、Callable接口的方式創建多線程的優缺點:
優點:
- 線程類只是實現了Runnable接口或Callable接口,還可以繼承其他類。
- 在這種方式下,多個線程可以共享同一個target對象,所以非常適合多個相同線程來處理同一份資源的情況,從而可以將CPU、代碼和數據分開、形成清晰地模型,較好的體現了面向對象的思想。
缺點:
- 編程稍稍複雜,如果需要訪問當前線程,則必須使用Thread.currentThread()方法。
採用繼承Thread類的方式創建多線程的優缺點:
優點:
- 編寫簡單,如果需要訪問當前線程,則無須使用Thread.currentThread()方法,直接使用this即可獲得當前線程。
缺點:
- 因爲繼承了Thread類,類只能進行單繼承,所以無法繼承其他的類。
總結
多線程是十分實用並且常用的內容,接下來小鹹兒還會繼續深入學習多線程,更多的內容等待更新。
感謝您的閱讀~~