Java多線程基本使用一

1? ? ? 多線程--初步

1進程

進程就是在系統(tǒng)中正在運行的程序

比如:QQ、迅雷、360囤攀、飛秋...

注意:操作系統(tǒng)中安裝了很多應(yīng)用程序,只有當開啟之后宫纬,系統(tǒng)才會為這個程序分配系統(tǒng)資源(CPU執(zhí)行權(quán)焚挠、內(nèi)存...)讓其運行在系統(tǒng)中

2線程的概念

線程是進程中的一個執(zhí)行路徑

3線程的意義:

每當一個進程開啟之后,系統(tǒng)會為這個一個進程分配系統(tǒng)資源漓骚,而線程是進程中的一部分蝌衔,當開啟一個線程之后,系統(tǒng)不會單獨為其分配內(nèi)存蝌蹂,而是一個進程中的多個線程共享它們所在的進程的資源噩斟,所以線程也可以理解為是輕量級的進程。

4.Java程序的運行原理

代碼是運行在線程中的孤个,如果一個進程沒有線程剃允,那么進程就結(jié)束了,也就是說一個進程至少要有一個線程

當開啟一個Java程序之后硼身,在進程中至少會自動創(chuàng)建兩個線程:主線程硅急、垃圾回收線程

實際上,使用多線程并不是為了提高程序運行的速度佳遂,而是為了提高CPU的使用率

多進程:在系統(tǒng)中同時運行著多個應(yīng)用程序营袜,并且多個進程(應(yīng)用程序)之間互不干擾

多線程:在進程中同時執(zhí)行著多個執(zhí)行路徑,并且多個線程(執(zhí)行路徑)之間互不干擾

使用場景:

迅雷下載丑罪、360多個任務(wù)的執(zhí)行荚板、QQ視屏和文件傳輸………

1.1????基本概念

for(int i=10;i<=100;i+=10){

System.out.println("洗衣服,進度"+i+"%");

Thread.sleep(500);

}

for(int i=0;i<=100;i+=10){

System.out.println("做飯,進度"+i+"%");

Thread.sleep(500);

}

//創(chuàng)建

WashThread wash = newWashThread();

CookThread cook = newCookThread();

//啟動

wash.start();

cook.start();

for(inti=10;i<=100;i+=10){

System.out.println("微波爐加熱吩屹,進度"+i+"%");

try {

Thread.sleep(500);

} catch(InterruptedException e) {

// TODOAuto-generated catch block

e.printStackTrace();

}

}

//每隔10秒打印Hello,同時可以接受用戶輸入跪另,并打印出來

Scanner s = newScanner(System.in);

PrintThread t = newPrintThread();

t.start();

while(true){

String line =s.nextLine();

System.out.println(line);

}

//選擇性學習

LagRunnable r = newLagRunnable();

ExecutorService service =Executors.newCachedThreadPool();

service.execute(r);

service.execute(r);

service.execute(r);

service.shutdown();

//**************************************

FileReader fr = newFileReader("g:/config.txt");

BufferedReader br = newBufferedReader(fr);

//?????????????? ReverseRunnable r =newReverseRunnable();

String name = br.readLine();

Class clz =Class.forName(name);

Runnable r=(Runnable)clz.newInstance();

//**************************************

//以上部分選擇性學習,擴展內(nèi)容

Thread t = new Thread(r);

t.start();

進程運行起來的程序

線程可以理解為一個子進程

進程間進行切換的代價較大煤搜,不能共享資源

線程間切換代價小免绿,可以共享數(shù)據(jù)和邏輯

Java進程每運行一個java應(yīng)用程序,就會啟動一個虛擬機進程擦盾,我們的程序就在其中運行

Java線程每個java進程中都默認有一個主線程嘲驾,名字為main

(我們之前的程序都是在主線程中執(zhí)行)

Thread類java中的線程,在一個線程中的代碼邏輯就像被一根線串起來一樣迹卢,從前往后順序執(zhí)行的

1.2????多線程

多線程辽故,創(chuàng)建主線程以外的子線程,讓多段邏輯"同時"執(zhí)行

腐碱,節(jié)省時間誊垢、避免程序阻塞帶來的問題

分時復用多個線程不停地快速切換使用CPU,表面上看是同時執(zhí)行,其實也是有先后順序的喂走,同一時間只有一個線程占有CPU殃饿。

1.3????線程的狀態(tài)

線程的狀態(tài):

創(chuàng)建-->就緒-->運行-->結(jié)束

運行-->阻塞--〉就緒

1.4????線程調(diào)度

假如當前計算機只有一個CPU且只有一個核心,那么CPU在某一個時刻只能執(zhí)行一條指令缴啡,線程只有得到CPU時間片壁晒,也就是使用權(quán)瓷们,才可以執(zhí)行指令业栅,那么Java是如何對線程進行調(diào)用的呢?

1.4.1? 線程有兩種調(diào)度模型

分時調(diào)度模型:所有線程輪流使用CPU的使用權(quán)谬晕,平均分配每個線程占用CPU的時間片

搶占調(diào)度模型:優(yōu)先讓優(yōu)先級高的線程使用CPU碘裕,如果線程的優(yōu)先級相同,那么會隨機選擇一個攒钳,優(yōu)先級高的線程獲取CPU時間片相對多一些

Java使用的是搶占式調(diào)度模型

1.4.2? 調(diào)整線程的優(yōu)先級

優(yōu)先級:獲取CPU資源的幾率

優(yōu)先級越高的線程會獲取越多的運行機會

優(yōu)先級的取值范圍是1-10之間的整數(shù)

Java將差別最大的三個優(yōu)先級定義成了Thread類中的靜態(tài)常量

MAX_PRIORITY:最高優(yōu)先級(10)

MIN_PRIORITY:最低優(yōu)先級(1)

NORM_PRIORITY:默認優(yōu)先級(5)

可以通過setPriority()和getPriority()方法進行設(shè)置和獲取

1.5????使用Thread繼承創(chuàng)建

線程的創(chuàng)建和使用

在Java中一切皆對象帮孔,線程這一類事物也用了一個類來進行了描述,這個類叫做Thread類

線程的創(chuàng)建

1不撑、繼承Thread類

2文兢、實現(xiàn)Runnable接口

兩種方式有什么區(qū)別?

1焕檬、 通過繼承Thread類會出現(xiàn)單繼承的問題姆坚,通過實現(xiàn)Runnable接口可以避免單繼承的不足

2、 通過實現(xiàn)Runnable接口可以將線程的任務(wù)從線程的子類中分離出來实愚,進行單獨的封裝兼呵,按照面向?qū)ο蟮乃枷雽⑷蝿?wù)封裝成了對象,并且可以方便實現(xiàn)多個線程的數(shù)據(jù)共享

一腊敲、使用Thread繼承創(chuàng)建

1击喂、定義一個類繼承Thread,重寫父類的run()方法,在run()中寫上要在子線程中執(zhí)行的邏輯

2碰辅、創(chuàng)建定義好的類懂昂,生成一個實例

3、調(diào)用這個實例的start(),啟動線程(不要調(diào)用run(),這個run()是一個回調(diào)方法)

1.6????Runnable(接口)方式

二没宾、Runnable(接口)方式

1凌彬、定義一個類實現(xiàn)Runnable接口,實現(xiàn)抽象方法run()榕吼,在run()中寫上要在子線程中執(zhí)行的邏輯

2饿序、創(chuàng)建一個Thread實例,從構(gòu)造方法參數(shù)傳入1中定義類的實例

3羹蚣、調(diào)用start()

Runnable方式從設(shè)計上耦合度更低原探,更靈活

1.7????數(shù)據(jù)共享

@Override

public void run() {

int progress = 0;? //初始化為0

while(true){

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

+"燒飯,進度"+progress+"%");

if(progress ==100){//進度到100停止循環(huán)

break;

}

try {

Thread.sleep(100);

} catch(InterruptedException e) {

// TODOAuto-generated catch block

e.printStackTrace();

}

progress++;?? //每次進度+1

}

}

Threadt1 = new Thread(new CookRunnable());

t1.start();

Thread t2 = new Thread(newCookRunnable());

t2.start();

CookRunnabler=newCookRunnable();

Threadt1=newThread(r);//兩個線程使用同一個Runnable對象

Threadt2=newThread(r);

//以下方式不能共享,因為是分別使用了兩個Runnable對象的兩個progress屬性

/* Thread t1 = new Thread(newCookRunnable());

Thread t2 = new Thread(newCookRunnable());*/

t1.start();//啟動

try{

Thread.sleep(50);//錯開50毫秒

}catch(InterruptedExceptione) {

//TODOAuto-generated catch block

e.printStackTrace();

}

t2.start();//啟動另一個線程

}

數(shù)據(jù)共享:

1咽弦、局部變量不能被多個線程共享

2徒蟆、成員變量可以被線程共享

1.8????常用方法

interrupt()方法:

Thread t = new Thread(new Runnable() {

@Override

publicvoid run() {

System.out.println("開始睡眠");

try{

Thread.sleep(20000);//睡眠20秒

}catch (InterruptedException e) {

//TODO Auto-generated catch block

System.out.println("睡到一半被斷了");

}

System.out.println("結(jié)束睡眠");

}

});

t.start();

try{

Thread.sleep(5000);

}catch (InterruptedException e) {

//TODO Auto-generated catch block

e.printStackTrace();

}

t.interrupt();//啟動子線程5秒后打斷它的睡眠

}

線程的優(yōu)先級:

t1.setPriority(1);

t2.setPriority(10);

t1.start();

t2.start();

Stop方法讓線程停下:

public class CycleRunnable implements Runnable{

privateboolean control = true;

publicvoid setControl(boolean control) {

this.control= control;

}

@Override

publicvoid run() {

while(control){

try{

Thread.sleep(3000);

}catch (InterruptedException e) {

//TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

publicstatic void main(String[] args) {

CycleRunnabler =new CycleRunnable();

Threadt = new Thread(r);

t.setName("停不下來的線程");//設(shè)置線程名字

t.start();

Scanners = new Scanner(System.in);

while(true){

Stringline = s.nextLine();

System.out.println("line="+line);

if(line.equals("stop")){

r.setControl(false);

break;

}

}

}

禮讓Yield():

Thread t2 = new Thread(new Runnable() {

@Override

publicvoid run() {

for(inti=1;i<=1000;i++){

System.out.println("????? "+i);

Thread.yield();//讓給別的線程使用CPU

//讓當前正在執(zhí)行的線程釋放CPU資源,讓其他線程有機會去搶占CPU資源

//有可能在釋放CPU資源之后型型,立馬自己又再搶到了CPU資源

}

}

});

Thread.currentThread()通過Thread的靜態(tài)方法獲得當前線程的對象段审,還可以調(diào)用這個對象的getName()方法獲取其名字

Thread.sleep(longm)通過這個靜態(tài)方法,可以睡眠m毫秒闹蒜,當前線程睡眠

setName(Stringn)設(shè)置線程名

intgetPriority()獲取優(yōu)先級寺枉,數(shù)字越大優(yōu)先級越高,優(yōu)先級高則搶占CPU成功的概率高一些绷落,優(yōu)先級范圍1-10姥闪,默認5

setPriority(intp)設(shè)置優(yōu)先級

yield()讓出CPU使用權(quán),但可以馬上再搶回來

interrupt()方法砌烁,能打斷一個線程sleep()筐喳、wait()、join()等方法函喉,能讓這些方法拋出InterruptedException

join()會合避归,等待子線程直到它結(jié)束,加入當前正在運行的線程管呵,等待加入的線程執(zhí)行完梳毙,再繼續(xù)執(zhí)行被加入的線程

setDaemon(boolean)方法將指定的線程設(shè)置為后臺線程,設(shè)置守護線程撇寞,所有前臺線程都結(jié)束后顿天,后臺線程(守護線程)會自動結(jié)束,該方法要在start()方法之前調(diào)用

線程加入:

public class ThreadJoinDemo{

public static void main(String[] args) throwsInterruptedException {

//線程加入

ThreadJoin t1 = new ThreadJoin("線程A");

ThreadJoin t2 = new ThreadJoin("線程B");

ThreadJoin t3 = new ThreadJoin("線程C");

t1.start();

/**

* 加入線程蔑担,讓指定的線程(t1)加入到當前正在運行的線程(主線程)中

* 并且保證指定的線程執(zhí)行完之后牌废,在繼續(xù)執(zhí)行當前線程

*/

t2.start();

t1.join();

t3.start();

}

}

class ThreadJoin extends Thread{

public ThreadJoin(String name){

super(name);

}

public void run(){

for(int i=0;i<10;i++){

try {

Thread.sleep(500);

System.out.println(Thread.currentThread().getName()+"......."+i);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

守護線程(后臺線程):

public classThreadDaemonDemo {

public static void main(String[] args) throwsInterruptedException {

// 設(shè)置守護線程

ThreadDaemon t1 = new ThreadDaemon("線程A");

ThreadDaemon t2 = new ThreadDaemon("線程B");

ThreadDaemon t3 = new ThreadDaemon("線程C");

t1.start();

Thread.sleep(5000);

/*

* 設(shè)置守護線程(后臺線程)

* 開啟的線程默認都是前臺線程,可以通過setDaemon(boolean)方法將指定線程設(shè)置為后臺線程啤握,

* 當所有前臺線程都結(jié)束之后鸟缕,后臺線程會自動結(jié)束(無論有沒有執(zhí)行完)

*

* 現(xiàn)在,t1和主線程是前臺線程排抬,而t2和t3被設(shè)置為后臺線程懂从,也就是說當t1和主線程都結(jié)束之后,

* 也就代表前臺線程全部結(jié)束了蹲蒲,那么兩個后臺線程(t2和t3)會自動結(jié)束

*/

t2.setDaemon(true);

t3.setDaemon(true);

t2.start();

t3.start();

}

}

class ThreadDaemon extendsThread {

public ThreadDaemon(String name) {

super(name);

}

@Override

public void run() {

for (int i = 1; i <= 20; i++) {

try {

Thread.sleep(500);

System.out.println(getName() +"..." +i);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

線程停止:

public class ThreadStop {

public static void main(String[] args) throwsInterruptedException {

Stops t1 = new Stops("線程A");

t1.start();

// 3秒之后停止子線程運行

Thread.sleep(3000);

// 1)使用stop方法

// t1.stop();

// 2)設(shè)置標記

// 停止線程最本質(zhì)的原理其實就是讓run()方法執(zhí)行完

// t1.setFlag(false);

// 3)使用interrupt方法

t1.interrupt();

// System.out.println("結(jié)束線程");

}

}

class Stops extends Thread{

private boolean runFlag = true;

public Stops(String name){

super(name);

}

@Override

public void run() {

// while(flag) {

while(!isInterrupted()) { // 判斷中斷標記是否為true

System.out.println("子線程...");

try {

/*

* 阻塞狀態(tài)會被中斷標記終止番甩,如果是被強制終止阻塞狀態(tài)的話會拋出中斷異常(InterruptedException)

* 并且在結(jié)束阻塞狀態(tài)之后,會清除中斷標記(也就是說isInterrupted()返回值為false)

*/

Thread.sleep(6000);

} catch (InterruptedException e) {

//打印異常信息

// e.printStackTrace();

break;

}

}

System.out.println("線程已經(jīng)運行完畢...");

}

public? voidsetFlag(boolean flag){

this.runFlag = flag;

}

}

1.8.1? 線程停止

1.stop()方法届搁,不建議使用,要讓線程結(jié)束缘薛,就讓它執(zhí)行完;可以使用一個條件變量作為線程中循環(huán)條件窍育,然后在外界通過控制這個變量,來使得線程結(jié)束(終止線程宴胧,已被廢棄漱抓,不推薦使用)

2、設(shè)置標記

3.interrupt():中斷線程的阻塞狀態(tài)恕齐,調(diào)用該方法之后乞娄,線程會標記一個中斷標記,當線程處于阻塞(比如休眠) 狀態(tài)時显歧,如果線程具備中斷狀態(tài)仪或,就會直接中斷當前的阻塞狀態(tài),并去除中斷標記

(isInterrupted():測試線程是否已經(jīng)中斷)

PS:停止線程最本質(zhì)的原理其實就是讓run()方法執(zhí)行完

1.9????線程的生命周期

生命周期:生命周期:從創(chuàng)建到結(jié)束的整個過程追迟,在這期間會包含很多階段(狀態(tài))

新建狀態(tài)(New):MyThread??t1 = new MyThread();

就緒狀態(tài)(Runnable):調(diào)用start()方法,使線程具有了運行資格溶其,但是沒有CPU的執(zhí)行權(quán)(就緒隊列:CPU在分配執(zhí)行權(quán)的時候是在就緒隊列中隨機和挑選一個線程并分配其執(zhí)行權(quán)(CPU調(diào)度))骚腥,等待CPU調(diào)度

運行狀態(tài)(Running):獲取了CPU的執(zhí)行權(quán)敦间,只有在運行狀態(tài)下的線程才具備CPU的執(zhí)行權(quán)

阻塞狀態(tài)(Blocked):在運行狀態(tài)下調(diào)用了sleep、wait或其他的一切方法使線程進入阻塞狀態(tài)(睡眠池束铭、等待池)

【sleep(毫秒值)《睡眠池:一塊內(nèi)存池廓块,集合對象或數(shù)組》?? wait()《等待池》】

《睡眠結(jié)束(時間結(jié)束或被中斷)被喚醒(notify) -à>>>會再次進入就緒狀態(tài)》

死亡狀態(tài)(Dead):stop()??? run()執(zhí)行完《線程一旦結(jié)束進入死亡之后,就沒有用了契沫,該狀態(tài)是不可逆的》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末带猴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子懈万,更是在濱河造成了極大的恐慌拴清,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件会通,死亡現(xiàn)場離奇詭異口予,居然都是意外死亡,警方通過查閱死者的電腦和手機涕侈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門沪停,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人裳涛,你說我怎么就攤上這事木张。” “怎么了端三?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵舷礼,是天一觀的道長。 經(jīng)常有香客問我郊闯,道長妻献,這世上最難降的妖魔是什么浮声? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮旋奢,結(jié)果婚禮上泳挥,老公的妹妹穿的比我還像新娘。我一直安慰自己至朗,他們只是感情好屉符,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锹引,像睡著了一般矗钟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嫌变,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天吨艇,我揣著相機與錄音,去河邊找鬼腾啥。 笑死东涡,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的倘待。 我是一名探鬼主播疮跑,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼凸舵!你這毒婦竟也來了祖娘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤啊奄,失蹤者是張志新(化名)和其女友劉穎渐苏,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體菇夸,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡琼富,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了峻仇。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片公黑。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖摄咆,靈堂內(nèi)的尸體忽然破棺而出凡蚜,到底是詐尸還是另有隱情,我是刑警寧澤吭从,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布朝蜘,位于F島的核電站鳍怨,受9級特大地震影響署咽,放射性物質(zhì)發(fā)生泄漏枷颊。R本人自食惡果不足惜夺蛇,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望副渴。 院中可真熱鬧奈附,春花似錦、人聲如沸煮剧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勉盅。三九已至佑颇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間草娜,已是汗流浹背挑胸。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宰闰,地道東北人茬贵。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像议蟆,于是被迫代替她去往敵國和親闷沥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容