1.線程的概念:線程(thread)是指一個(gè)任務(wù)從頭至尾的執(zhí)行流,線程提供一個(gè)運(yùn)行任務(wù)的機(jī)制,對(duì)于java而言,一個(gè)程序中可以并發(fā)的執(zhí)行多個(gè)線程,這些線程可以在多處理器系統(tǒng)上同時(shí)運(yùn)行。當(dāng)程序作為一個(gè)應(yīng)用程序運(yùn)行時(shí),java解釋器為main()方法啟動(dòng)一個(gè)線程。
成都創(chuàng)新互聯(lián)專注于企業(yè)營(yíng)銷型網(wǎng)站、網(wǎng)站重做改版、天涯網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5頁(yè)面制作、商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)公司、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為天涯等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。
2.并行與并發(fā):
(1)并發(fā):在單處理器系統(tǒng)中,多個(gè)線程共享CPU時(shí)間,而操作系統(tǒng)負(fù)責(zé)調(diào)度及分配資源給它們。
(2)并行:在多處理器系統(tǒng)中,多個(gè)處理器可以同時(shí)運(yùn)行多個(gè)線程,這些線程在同一時(shí)間可以同時(shí)運(yùn)行,而不同于并發(fā),只能多個(gè)線程共享CPU時(shí)間,同一時(shí)間只能運(yùn)行一個(gè)線程。
3.線程的創(chuàng)建:
(1)基礎(chǔ)概念:java中每個(gè)任務(wù)就是一個(gè)可運(yùn)行對(duì)象,為了創(chuàng)建任務(wù),必須首先定義任務(wù)類,任務(wù)類必須實(shí)現(xiàn)Runnable接口。而線程本質(zhì)上講就是便于任務(wù)執(zhí)行的對(duì)象。一個(gè)線程的執(zhí)行過(guò)程就是一個(gè)任務(wù)類中run()方法的執(zhí)行到結(jié)束。
(2)通過(guò)Runnable接口創(chuàng)建線程:
a.定義一個(gè)任務(wù)類實(shí)現(xiàn)Runnable接口,實(shí)現(xiàn)Runnable接口中的run()方法(run()方法告知系統(tǒng)線程該如何運(yùn)行),run()方法中定義具體的任務(wù)代碼或處理邏輯。
b.定義了任務(wù)類后,為任務(wù)類創(chuàng)建一個(gè)任務(wù)對(duì)象。
c.任務(wù)必須在線程中執(zhí)行,創(chuàng)建一個(gè)Tread類的對(duì)象,將前面創(chuàng)建的實(shí)現(xiàn)了Runnable接口的任務(wù)類對(duì)象作為參數(shù)傳遞給Tread類的構(gòu)造方法。
d.調(diào)用Tread類對(duì)象的start()方法,啟動(dòng)一個(gè)線程。它會(huì)導(dǎo)致任務(wù)的run()方法被執(zhí)行,當(dāng)run()方法執(zhí)行完畢,則線程就終止。
實(shí)例代碼:
package com.muzeet.mutithread; //每個(gè)任務(wù)都是Runable接口的一個(gè)實(shí)例,任務(wù)是可運(yùn)行對(duì)象,線程是便于任務(wù)執(zhí)行的對(duì)象。必須創(chuàng)建任務(wù)類,重寫(xiě)run方法定義任務(wù) public class ThreadDemo1 implements Runnable { private int countDown = 10; @Override //重寫(xiě)run方法,定義任務(wù) public void run() { while(countDown-- >0) { System.out.println("$" + Thread.currentThread().getName() + "(" + countDown + ")"); } } //調(diào)用start方法會(huì)啟動(dòng)一個(gè)線程,導(dǎo)致任務(wù)中的run方法被調(diào)用,run方法執(zhí)行完畢則線程終止 public static void main(String[] args) { Runnable demo1 = new ThreadDemo1(); Thread thread1 = new Thread(demo1); Thread thread2 = new Thread(demo1); thread1.start(); thread2.start(); System.out.println("火箭發(fā)射倒計(jì)時(shí):"); } }
程序運(yùn)行結(jié)果:
火箭發(fā)射倒計(jì)時(shí): $Thread-0(9) $Thread-0(8) $Thread-0(7) $Thread-0(6) $Thread-0(5) $Thread-0(4) $Thread-0(3) $Thread-0(2) $Thread-0(1) $Thread-0(0)
同時(shí)運(yùn)行兩個(gè)任務(wù)對(duì)象:
public static void main(String[] args) { Runnable demo1 = new ThreadDemo1(); Runnable demo2 = new ThreadDemo1(); Thread thread1 = new Thread(demo1); Thread thread2 = new Thread(demo2); thread1.start(); thread2.start(); System.out.println("火箭發(fā)射倒計(jì)時(shí):"); }
運(yùn)行結(jié)果:
火箭發(fā)射倒計(jì)時(shí): $Thread-0(9) $Thread-0(8) $Thread-0(7) $Thread-0(6) $Thread-1(9) $Thread-0(5) $Thread-1(8) $Thread-0(4) $Thread-1(7) $Thread-0(3) $Thread-1(6) $Thread-1(5) $Thread-0(2) $Thread-1(4) $Thread-1(3) $Thread-1(2) $Thread-1(1) $Thread-1(0) $Thread-0(1) $Thread-0(0)
(3)繼承Thread類來(lái)創(chuàng)建線程:
a.首先創(chuàng)建一個(gè)任務(wù)類extends Thread類,因?yàn)門hread類實(shí)現(xiàn)了Runnable接口,所以自定義的任務(wù)類也實(shí)現(xiàn)了Runnable接口,重新run()方法,其中定義具體的任務(wù)代碼或處理邏輯。
b.創(chuàng)建一個(gè)任務(wù)類對(duì)象,可以用Thread或者Runnable作為自定義的變量類型。
c.調(diào)用自定義對(duì)象的start()方法,啟動(dòng)一個(gè)線程。
示例代碼:
package com.muzeet.mutithread; //每個(gè)任務(wù)都是Runable接口的一個(gè)實(shí)例,任務(wù)是可運(yùn)行對(duì)象,線程即可運(yùn)行對(duì)象。必須創(chuàng)建任務(wù)類,重寫(xiě)run方法定義任務(wù) public class ExtendFromThread extends Thread { private int countDown = 10; @Override //重寫(xiě)run方法,定義任務(wù) public void run() { while(countDown-- >0) { System.out.println("$" + this.getName() + "(" + countDown + ")"); } } //調(diào)用start方法會(huì)啟動(dòng)一個(gè)線程,導(dǎo)致任務(wù)中的run方法被調(diào)用,run方法執(zhí)行完畢則線程終止 public static void main(String[] args) { ExtendFromThread thread1 = new ExtendFromThread(); ExtendFromThread thread2 = new ExtendFromThread(); thread1.start(); thread2.start(); System.out.println("火箭發(fā)射倒計(jì)時(shí):"); } }
運(yùn)行結(jié)果:
火箭發(fā)射倒計(jì)時(shí): $Thread-0(9) $Thread-0(8) $Thread-0(7) $Thread-0(6) $Thread-0(5) $Thread-0(4) $Thread-0(3) $Thread-0(2) $Thread-0(1) $Thread-0(0) $Thread-1(9) $Thread-1(8) $Thread-1(7) $Thread-1(6) $Thread-1(5) $Thread-1(4) $Thread-1(3) $Thread-1(2) $Thread-1(1) $Thread-1(0)
一個(gè)線程等待另一個(gè)線程結(jié)束后再執(zhí)行:當(dāng)執(zhí)行PrintNum這個(gè)任務(wù)時(shí),打印到數(shù)字50時(shí),轉(zhuǎn)而去執(zhí)行打印字符C這個(gè)任務(wù),知道線程thread4執(zhí)行完才繼續(xù)執(zhí)行打印數(shù)字任務(wù)。
package com.muzeet.testThread; public class PrintNum implements Runnable { private int lastNum; public PrintNum(int n) { lastNum = n; } @Override public void run() { // TODO Auto-generated method stub Thread thread4 = new Thread(new PrintChar('c', 40)); thread4.start(); try { for(int i=1;i<=lastNum;i++) { System.out.println(" " + i); if(i == 50) { thread4.join(); } } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
4.兩種方法的比較(轉(zhuǎn)載)
首先分析兩種方式的輸出結(jié)果,同樣是創(chuàng)建了兩個(gè)線程,為什么結(jié)果不一樣呢?
使用實(shí)現(xiàn)Runnable接口方式創(chuàng)建線程可以共享同一個(gè)目標(biāo)對(duì)象(TreadDemo1tt=newTreadDemo1();),實(shí)現(xiàn)了多個(gè)相同線程處理同一份資源。當(dāng)?shù)谝粋€(gè)線程執(zhí)行完任務(wù)后,countDown已經(jīng)為0,所以第二個(gè)線程就不會(huì)輸出。而繼承Thread創(chuàng)建線程的方式,new出了兩個(gè)任務(wù)類對(duì)象,有各自的成員變量,相互之間不干擾。
然后再看一段來(lái)自JDK的解釋:
Runnable接口應(yīng)該由那些打算通過(guò)某一線程執(zhí)行其實(shí)例的類來(lái)實(shí)現(xiàn)。類必須定義一個(gè)稱為run的無(wú)參數(shù)方法。
設(shè)計(jì)該接口的目的是為希望在活動(dòng)時(shí)執(zhí)行代碼的對(duì)象提供一個(gè)公共協(xié)議。例如,Thread類實(shí)現(xiàn)了Runnable。激活的意思是說(shuō)某個(gè)線程已啟動(dòng)并且尚未停止。
此外,Runnable為非Thread子類的類提供了一種激活方式。通過(guò)實(shí)例化某個(gè)Thread實(shí)例并將自身作為運(yùn)行目標(biāo),就可以運(yùn)行實(shí)現(xiàn)Runnable的類。大多數(shù)情況下,如果只想重寫(xiě)run()方法,而不重寫(xiě)其他Thread方法,那么應(yīng)使用Runnable接口。這很重要,因?yàn)槌浅绦騿T打算修改或增強(qiáng)類的基本行為,否則不應(yīng)為該類創(chuàng)建子類。(推薦使用創(chuàng)建任務(wù)類,并實(shí)現(xiàn)Runnable接口,而不是繼承Thread類)
采用繼承Thread類方式:
(1)優(yōu)點(diǎn):編寫(xiě)簡(jiǎn)單,如果需要訪問(wèn)當(dāng)前線程,無(wú)需使用Thread.currentThread()方法,直接使用this,即可獲得當(dāng)前線程。
(2)缺點(diǎn):因?yàn)榫€程類已經(jīng)繼承了Thread類,所以不能再繼承其他的父類。
采用實(shí)現(xiàn)Runnable接口方式:
(1)優(yōu)點(diǎn):線程類只是實(shí)現(xiàn)了Runable接口,還可以繼承其他的類。在這種方式下,可以多個(gè)線程共享同一個(gè)目標(biāo)對(duì)象,所以非常適合多個(gè)相同線程來(lái)處理同一份資源的情況,從而可以將CPU代碼和數(shù)據(jù)分開(kāi),形成清晰的模型,較好地體現(xiàn)了面向?qū)ο蟮乃枷搿?/p>
(2)缺點(diǎn):編程稍微復(fù)雜,如果需要訪問(wèn)當(dāng)前線程,必須使用Thread.currentThread()方法。
總結(jié)
以上就是本文關(guān)于Java多線程中線程的兩種創(chuàng)建方式及比較代碼示例的全部?jī)?nèi)容,希望對(duì)大家有所幫助。如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!