java中多線程的實現(xiàn)方法有兩種:1.直接繼承thread類;2.實現(xiàn)runnable接口;同步的實現(xiàn)方法有五種:1.同步方法;2.同步代碼塊;3.使用特殊域變量(volatile)實現(xiàn)線程同步;4.使用重入鎖實現(xiàn)線程同步;5.使用局部變量實現(xiàn)線程同步
創(chuàng)新互聯(lián)是少有的成都網(wǎng)站建設、成都網(wǎng)站設計、營銷型企業(yè)網(wǎng)站、小程序開發(fā)、手機APP,開發(fā)、制作、設計、賣鏈接、推廣優(yōu)化一站式服務網(wǎng)絡公司,于2013年成立,堅持透明化,價格低,無套路經(jīng)營理念。讓網(wǎng)頁驚喜每一位訪客多年來深受用戶好評
。
其中多線程實現(xiàn)過程中需注意重寫或者覆蓋run()方法,而對于同步的實現(xiàn)方法中使用較常使用的是利用synchronized編寫同步方法和代碼塊。
1、public class MyThread extends Thread{//重寫run()方法public void run(){ //多線程要做的事}public static void main(String args[]){ MyThread m1 = new MyThread(); MyThread m2 = new MyThread(); m1.start(); m2.start();}} 2、public class NThread implements Runable{ //實現(xiàn)run()方法 public void run(){ //多線程要做的事 } public static void main(String args[]){ NThread nt = new NThread(); new Thread(nt,"nt1_name").start(); new Thread(nt,"nt2_name").start(); }}
在java中要想實現(xiàn)多線程,有兩種手段,一種是繼續(xù)Thread類,另外一種是實現(xiàn)Runable接口。
對于直接繼承Thread的類來說,代碼大致框架是:
?
123456789101112 class 類名 extends Thread{ 方法1; 方法2; … public void run(){ // other code… } 屬性1; 屬性2; … }
先看一個簡單的例子:
?
12345678910111213141516171819202122232425262728 /** * @author Rollen-Holt 繼承Thread類,直接調(diào)用run方法 * */class hello extends Thread { public hello() { } public hello(String name) { this.name = name; } public void run() { for (int i = 0; i 5; i++) { System.out.println(name + "運行 " + i); } } public static void main(String[] args) { hello h1=new hello("A"); hello h2=new hello("B"); h1.run(); h2.run(); } private String name; }
【運行結(jié)果】:
A運行 0
A運行 1
A運行 2
A運行 3
A運行 4
B運行 0
B運行 1
B運行 2
B運行 3
B運行 4
我們會發(fā)現(xiàn)這些都是順序執(zhí)行的,說明我們的調(diào)用方法不對,應該調(diào)用的是start()方法。
當我們把上面的主函數(shù)修改為如下所示的時候:
?
123456 public static void main(String[] args) { hello h1=new hello("A"); hello h2=new hello("B"); h1.start(); h2.start(); }
然后運行程序,輸出的可能的結(jié)果如下:
A運行 0
B運行 0
B運行 1
B運行 2
B運行 3
B運行 4
A運行 1
A運行 2
A運行 3
A運行 4
因為需要用到CPU的資源,所以每次的運行結(jié)果基本是都不一樣的,呵呵。
注意:雖然我們在這里調(diào)用的是start()方法,但是實際上調(diào)用的還是run()方法的主體。
那么:為什么我們不能直接調(diào)用run()方法呢?
我的理解是:線程的運行需要本地操作系統(tǒng)的支持。
如果你查看start的源代碼的時候,會發(fā)現(xiàn):
?
1234567891011121314151617 public synchronized void start() { /** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */ if (threadStatus != 0 || this != me) throw new IllegalThreadStateException(); group.add(this); start0(); if (stopBeforeStart) { stop0(throwableFromStop); } } private native void start0();
注意我用紅色加粗的那一條語句,說明此處調(diào)用的是start0()。并且這個這個方法用了native關(guān)鍵字,次關(guān)鍵字表示調(diào)用本地操作系統(tǒng)的函數(shù)。因為多線程的實現(xiàn)需要本地操作系統(tǒng)的支持。
但是start方法重復調(diào)用的話,會出現(xiàn)java.lang.IllegalThreadStateException異常。
通過實現(xiàn)Runnable接口:
大致框架是:
?
123456789101112 class 類名 implements Runnable{ 方法1; 方法2; … public void run(){ // other code… } 屬性1; 屬性2; … }
來先看一個小例子吧:
?
123456789101112131415161718192021222324252627282930 /** * @author Rollen-Holt 實現(xiàn)Runnable接口 * */class hello implements Runnable { public hello() { } public hello(String name) { this.name = name; } public void run() { for (int i = 0; i 5; i++) { System.out.println(name + "運行 " + i); } } public static void main(String[] args) { hello h1=new hello("線程A"); Thread demo= new Thread(h1); hello h2=new hello("線程B"); Thread demo1=new Thread(h2); demo.start(); demo1.start(); } private String name; }
【可能的運行結(jié)果】:
線程A運行 0
線程B運行 0
線程B運行 1
線程B運行 2
線程B運行 3
線程B運行 4
線程A運行 1
線程A運行 2
線程A運行 3
線程A運行 4
關(guān)于選擇繼承Thread還是實現(xiàn)Runnable接口?
其實Thread也是實現(xiàn)Runnable接口的:
?
12345678 class Thread implements Runnable { //… public void run() { if (target != null) { target.run(); } } }
其實Thread中的run方法調(diào)用的是Runnable接口的run方法。不知道大家發(fā)現(xiàn)沒有,Thread和Runnable都實現(xiàn)了run方法,這種操作模式其實就是代理模式。關(guān)于代理模式,我曾經(jīng)寫過一個小例子呵呵,大家有興趣的話可以看一下:
Thread和Runnable的區(qū)別:
如果一個類繼承Thread,則不適合資源共享。但是如果實現(xiàn)了Runable接口的話,則很容易的實現(xiàn)資源共享。
?
1234567891011121314151617181920212223 /** * @author Rollen-Holt 繼承Thread類,不能資源共享 * */class hello extends Thread { public void run() { for (int i = 0; i 7; i++) { if (count 0) { System.out.println("count= " + count--); } } } public static void main(String[] args) { hello h1 = new hello(); hello h2 = new hello(); hello h3 = new hello(); h1.start(); h2.start(); h3.start(); } private int count = 5; }
【運行結(jié)果】:
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1
大家可以想象,如果這個是一個買票系統(tǒng)的話,如果count表示的是車票的數(shù)量的話,說明并沒有實現(xiàn)資源的共享。
我們換為Runnable接口:
?
12345678910111213141516171819 /** * @author Rollen-Holt 繼承Thread類,不能資源共享 * */class hello implements Runnable { public void run() { for (int i = 0; i 7; i++) { if (count 0) { System.out.println("count= " + count--); } } } public static void main(String[] args) { hello he=new hello(); new Thread(he).start(); } private int count = 5; }
【運行結(jié)果】:
count= 5
count= 4
count= 3
count= 2
count= 1
總結(jié)一下吧:
實現(xiàn)Runnable接口比繼承Thread類所具有的優(yōu)勢:
1):適合多個相同的程序代碼的線程去處理同一個資源
2):可以避免java中的單繼承的限制
3):增加程序的健壯性,代碼可以被多個線程共享,代碼和數(shù)據(jù)獨立。
所以,本人建議大家勁量實現(xiàn)接口。
?
Java 給多線程編程提供了內(nèi)置的支持。 一條線程指的是進程中一個單一順序的控制流,一個進程中可以并發(fā)多個線程,每條線程并行執(zhí)行不同的任務。
新建狀態(tài):
使用 new 關(guān)鍵字和 Thread 類或其子類建立一個線程對象后,該線程對象就處于新建狀態(tài)。它保持這個狀態(tài)直到程序 start() 這個線程。
就緒狀態(tài):
當線程對象調(diào)用了start()方法之后,該線程就進入就緒狀態(tài)。就緒狀態(tài)的線程處于就緒隊列中,要等待JVM里線程調(diào)度器的調(diào)度。
運行狀態(tài):
如果就緒狀態(tài)的線程獲取 CPU 資源,就可以執(zhí)行 run(),此時線程便處于運行狀態(tài)。處于運行狀態(tài)的線程最為復雜,它可以變?yōu)樽枞麪顟B(tài)、就緒狀態(tài)和死亡狀態(tài)。
阻塞狀態(tài):
如果一個線程執(zhí)行了sleep(睡眠)、suspend(掛起)等方法,失去所占用資源之后,該線程就從運行狀態(tài)進入阻塞狀態(tài)。在睡眠時間已到或獲得設備資源后可以重新進入就緒狀態(tài)??梢苑譃槿N:
等待阻塞:運行狀態(tài)中的線程執(zhí)行 wait() 方法,使線程進入到等待阻塞狀態(tài)。
同步阻塞:線程在獲取 synchronized 同步鎖失敗(因為同步鎖被其他線程占用)。
其他阻塞:通過調(diào)用線程的 sleep() 或 join() 發(fā)出了 I/O 請求時,線程就會進入到阻塞狀態(tài)。當sleep() 狀態(tài)超時,join() 等待線程終止或超時,或者 I/O 處理完畢,線程重新轉(zhuǎn)入就緒狀態(tài)。
死亡狀態(tài):
一個運行狀態(tài)的線程完成任務或者其他終止條件發(fā)生時,該線程就切換到終止狀態(tài)。
繼承Thread類來實現(xiàn)多線程:
當我們自定義的類繼承Thread類后,該類就為一個線程類,該類為一個獨立的執(zhí)行單元,線程代碼必須編寫在run()方法中,run方法是由Thread類定義,我們自己寫的線程類必須重寫run方法。
run方法中定義的代碼為線程代碼,但run方法不能直接調(diào)用,如果直接調(diào)用并沒有開啟新的線程而是將run方法交給調(diào)用的線程執(zhí)行
要開啟新的線程需要調(diào)用Thread類的start()方法,該方法自動開啟一個新的線程并自動執(zhí)行run方法中的內(nèi)容
? ? ?
請點擊輸入圖片描述
結(jié)果: ? ? ? ? ? ?
? ? ?
請點擊輸入圖片描述
*java多線程的啟動順序不一定是線程執(zhí)行的順序,各個線程之間是搶占CPU資源執(zhí)行的,所有有可能出現(xiàn)與啟動順序不一致的情況。
CPU的調(diào)用策略:
如何使用CPU資源是由操作系統(tǒng)來決定的,但操作系統(tǒng)只能決定CPU的使用策略不能控制實際獲得CPU執(zhí)行權(quán)的程序。
線程執(zhí)行有兩種方式:
1.搶占式:
目前PC機中使用最多的一種方式,線程搶占CPU的執(zhí)行權(quán),當一個線程搶到CPU的資源后并不是一直執(zhí)行到此線程執(zhí)行結(jié)束,而是執(zhí)行一個時間片后讓出CPU資源,此時同其他線程再次搶占CPU資源獲得執(zhí)行權(quán)。
2.輪循式;
每個線程執(zhí)行固定的時間片后讓出CPU資源,以此循環(huán)執(zhí)行每個線程執(zhí)行相同的時間片后讓出CPU資源交給下一個線程執(zhí)行。
本文標題:多線程java代碼實現(xiàn),java多線程實現(xiàn)的代碼
標題路徑:http://sd-ha.com/article26/hdhcjg.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供域名注冊、網(wǎng)站建設、全網(wǎng)營銷推廣、動態(tài)網(wǎng)站、響應式網(wǎng)站、App設計
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)