深入理解並發編程 -- 多線程(一)


並發編程 -- 多線程(一)

作者 : Stanley 羅昊

轉載請注明出處和署名,謝謝!

進程

在理解多線程之前,我們先需要了解什么是進程?

進程說白了就是在你的內存空間中開辟出的一個獨立的空間;

如果還不理解的話,我再解釋一下;

想必各位之前都安裝過軟件吧,你安裝完軟件之后,在你的軟件安裝包里面是不是有一個.exe文件,那你雙擊exe文件的時候,在你的任務管理器,在里面就有一個進程選項卡,就是說,每當你打開一個exe文件的時候,它都會顯示在任務管理器的進程當中,所以就可以把運行中的任意一款軟件,都可以把它看做一個進程;

當然,以上的操作方式是在windows系統的操作的,也就是說,想查看Windows的進程,只需要在任務管理器中查看即可;

在linux下使用命令 ps 或 pstree、ps -eflgrep;

如果想在linux系統下查看java的相關進程,命令為:jps;

那么問題就來了,當你打開QQ的時候,是不是就是開啟了一個進程,當你開始使用它並且聊天的時候,比如你是a,你現在要跟b聊天然后再去跟c聊天,那么這樣的操作是不是相互獨立的呢?也就是說,你現在要跟b發送你的游戲密碼,這個時候c問你晚上吃啥飯,你發的密碼c知道嗎?肯定不會啦,所以你跟b聊天的時候,是不會影響你跟c聊天的,因為你跟b c 是相互獨立的

那么,在這個里面,你跟他們每個人產生的通話底層是怎么實現的呢?

底層就是靠線程去實現的;

線程

什么是線程呢?

線程是指程序在執行過程中,能夠執行程序代碼的一個執行單元,在Java語言中,線程有四種狀態:運行,就緒,掛起,結束。一般情況下,一個操作系統是有多個進程,那么每個進程都要對應多個線程;

線程與進程有區別嗎?

,進程是一段正在運行的程序,而線程有時也被稱為輕量級進程,它是進程的執行單元,一個進程可以擁有多個線程,各個線程之間共享程序的內存空間,但是,各個線程擁有自己的棧空間。

一個進程可以有很多線程,每條線程並行執行不同的任務;

實現單個線程

在之前的一些簡單的java練習中,我們運行的時候,是不是都是在main方法中測試運行啊,那么,在這之前,我僅僅編寫了一些非常簡單的java代碼,甚至就在main方法中輸出了一句話,就可以直接完成運行,在這期間,我並沒有創建有關線程方面的方法以及程序,那么就怎么實現運行了呢?

其實很簡單,Main方法既然能運行你的程序,那么必然就會有一個線程,那么這個線程就是單線程,那,我們如何查看本次運行線程的線程名呢?

我們僅需在main方法里面輸出以下即可:

System.out.println(Thread.currentThread());

打印出來后,我們就可以看到線程名師Main,因為就一個線程,所以main就是主線程;

那么就一個線程,就表明,在這之前,我們所做的一些練習程序都是單線程的;

線程的創建方式

兩種:

1.繼承(extends) Thread

繼承完Thread類之后需要重寫run方法;

2.實現(implem) Runnable接口

也許需要重寫run方法;

繼承Thread類創建線程

講了那么多,那么就開始上手實操一下,我們將要練習的是繼承Thread來創建一個線程;

首先,我們創建一個類(MyThread)然后繼承Thread類;

繼承完Thread后,實現run方法;

run方法的作用就是,相當於這個線程對用戶提供的一個接口;

所以,用戶有什么業務邏輯,都需要寫在run方法里面:

public class MyThread extends Thread{

    public void run(){

                  //作用:相當於這個線程向用戶提供的接口,用戶有什么樣的業務邏輯,寫在這個方法中

    }

}

那我們現在就讓這個run方法就實現一個簡單的打印;

這個就是我使用了第一種方式來創建了一個線程;

那么,你這個線程創建完成后,如果你想調用它怎么辦?

調用線程

我再建一個類(TestThread);

然后提供一個Main方法;

在main方法中創建一個線程,語法:

//創建一個線程

MyThread mt = new MyThred();

這個就是創建線程,創建完后,下一步我們需要調用start方法;

public class TestThread{

public static void main (String [] args){

//創建線程

MyThread mt = new MyThred();

//啟動線程

mt.start();

       }

   }

為什么要調用start,而不是run?

其實很簡單,mt.start就是啟動你的線程,那么啟動后,它底層就會去調用你的run方法;

這個就是線程的啟動式start方法;

我們運行一下后,看一下控制台打印:

就是一些輸出,感覺就跟調用方法一樣,對吧;

那么,接下來,我們看一下第二種創建方式

實現(implem) Runnable接口創建線程

這種方法跟上面的那種,大同小異,只不過上面那個是繼承,這個是實現接口;

實現Runnable接口后,需要實現它的run方法;

public class MyRunnableThread implements Runable{

    public void run(){

                  //作用:相當於這個線程向用戶提供的接口,用戶有什么樣的業務邏輯,寫在這個方法中

    }

}

現在,我們用第二種方式創建了一個線程,當然,業務邏輯跟上面的那個相同,因為舉例,所以沒有深究別的;

第二種方式調用線程就有所不同

 因為運行線程永遠需要Thread里面的start方法來啟動線程,所以需要把Thread創建出來,再將創建出來的線程放進去;

所以打印出來的結果是跟上面的結果是一樣的,這里就不再放圖上去了;

線程關鍵字分析

start,是線程啟動的方法;

run方法是線程執行過程中調用的方法(默認調用),在上面的例子我們也看到了,你並沒有手動去調用run方法,是他自動調用的,就跟你創建對象的時候,默認調用構造方法一樣;

深究run與start

那,啟動線程一定是要用staet方法啟動,我試試不用它,我直接調用Thread中的run方法可行嗎?

可行因為拋開線程,你本身就是實例化了Thread這個類,並調用該類中的run方法是沒有問題的,但是,不納入線程中!!

我們直接調用run方法后,發現,方法可以正常打印,因為,僅僅完成了普通方法的調用,實際上並沒有啟動線程;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM