天天看點

Java多線程

一、程式、程序、線程:

程式:指令集、靜态概念

程序:OS排程程式、動态概念。資源配置設定的機關。

線程:在程序内多條執行路徑。線程又被稱為輕量級的程序,一個程序可擁有多個并行的線程。容易造成并發的問題。main、gc和異常分别是不同的線程。排程和執行的機關。

二、Java實作多線程:

繼承java.lang.Thread,重寫run()方法:

啟動:建立子類對象+對象.start()。

下面程式使用繼承Thread類方式,模拟3個程序同時運作(包括一個主線程main)。

常用工具:Thread.sleep(long millis)

Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.

例如:Thread.sleep(2000); 程式休息2秒。

2. 實作Runnable接口:

啟動:a.建立真實角色;b.建立代理角色+引用;c.代理角色.start()。

繼承Thread類建立的方式,有弱點。因為java是單繼承方式的。

Runnable使用了“靜态代理”的設計模式。我們編寫的實作了Runnable接口的類是真實類,Thread類是代理類。真實類和Thread類都實作了Runnable接口,在代理類Thread中聲明了Runnable屬性target。

(1)靜态代理模式:

(2)使用Runnable建立線程:

建立真實角色(我們自己的類);

建立代理角色 + 真實角色引用;

調用start() 啟動線程。

使用Runnable的好處:

a.避免單繼承

b.友善共享資源

繼承Runnable實作的多線程執行個體:

使用實作Runnable接口的方式來實作線程,可以友善“資源共享”,下面是一個搶票的例子。

(3)實作Callable接口方式,實作多線程:

Callable接口與Runnable接口類似,但是該接口可以傳回值或者抛出異常。

Callable 和 Future 接口 

Callable是類似于Runnable的接口,實作Callable接口的類和實作Runnable的類都是可被其它線程執行的任務。 

Callable和Runnable有幾點不同:  

(1)Callable規定的方法是call(),而Runnable規定的方法是run(). 

(2)Callable的任務執行後可傳回值,而Runnable的任務是不能傳回值的。  

(3)call()方法可抛出異常,而run()方法是不能抛出異常的。 

(4)運作Callable任務可拿到一個Future對象, Future表示異步計算的結果。 

它提供了檢查計算是否完成的方法,以等待計算的完成,并檢索計算的結果。 

通過Future對象可了解任務執行情況,可取消任務的執行,還可擷取任務執行的結果。涉及到ExecutorService、Executors、Future幾個類和接口的使用:

下面例子是用實作Callable接口實作的線程:

三、線程的狀态:

線程的五大狀态:

Java多線程

線程從建立、運作到結束總是處于下面五個狀态之一:

建立狀态、就緒狀态、運作狀态、阻塞狀态及死亡狀态(終止)。

2.停止狀态:

a.自然終止:線程體正常執行完畢

b.外部幹涉:

(1)線程類中 線程體使用的辨別

(2)線程體内使用該辨別

(3)提供對外的方法改變該辨別

(4)外部根據條件調用該方法

Thread的stop和destry (已經過時),不安全,建議不要使用。

下面程式示範了線程的外部幹涉終止的執行個體:

3. 阻塞狀态:

a.join:合并線程:

被join進來的線程會先執行完。

b.yield:暫停程序:

yield方法并沒有完全意義上的暫停,隻是暫時釋放資源給CPU,讓CPU執行其他未執行完的線程。也有可能在下一個時鐘周期,CPU又開始執行這個線程了。

yield()是一個靜态方法,使用Thread.yield()。 這個方法寫在哪個線程體裡,就暫停哪個線程。

API上的說明:

It is rarely appropriate to use this method. It may be useful for debugging or testing purposes, where it may help to reproduce bugs due to race conditions. It may also be useful when designing concurrency control constructs such as the ones in the java.util.concurrent.locks package.

JoinYieldDemo01.java

c.sleep方法:

休眠,不釋放鎖。 每一個對象都會生成一個鎖,占用一定的資源。在sleep時,不釋放鎖。

sleep方法的應用:1.與時間相關的,倒計時  2.模拟網絡延時。

下例子展示了時間倒計時的程式:

SleepDemo01.java:

網絡阻塞模拟程式SleepDemo2.java:

下邊程式,由于三個線程共享“餘票”資源,是以會發生并發的錯誤。産生了0張票,-1張票的錯誤,因為在判斷第1張票時,由于之前的2個線程都進行了sleep,是以他們都會通過條件“if (TicketNum > 0)”,是以在第一個線程-1後,後2個線程也都-1,就出現了錯誤(0和-1張票)。

四、線程的基本資訊:

Thread.currentThread():目前線程。

setName():設定名稱;

getName():擷取名稱:

isAlive():判斷狀态。

getPriority():擷取優先級

setPriority():設定優先級

MIN_PRIORITY:1

MAX_PRIORITY:10

NORM_PRIORITY:5

優先級:代表的是機率,不是絕對的優先級,不代表絕對的先後順序。例如線程t1和t2,如果t1的優先級比t2的優先級高,不代表執行t1不執行t2,而是t1執行的機率比t2的高。

MyThread.java

Info1.java:

Info2.java:

上一篇: java多線程
下一篇: java多線程

繼續閱讀