1.
進程:每個進程都有獨立的代碼和數(shù)據(jù)空間(進程上下文)
,進程切換的開銷大。線程:同一類線程共享代碼和數(shù)據(jù)空間,每個線程有獨立的運行棧和程序計數(shù)器(PC),線程切換的開銷小。
[SaleMan1]Book0 sold
out:true. by Thread-0
[SaleMan2]Book1 sold out:true. by
Thread-1
[SaleMan2]Book2 sold out:true. by Thread-1
[SaleMan2]Book3 sold
out:true. by Thread-1
[SaleMan2]Book4 sold out:true. by
Thread-1
[SaleMan2]Book5 sold out:true. by Thread-1
[SaleMan1]Book6 sold
out:true. by Thread-0
[SaleMan1]Book7 sold out:true. by
Thread-0
[SaleMan1]Book8 sold out:true. by Thread-0
[SaleMan1]Book9 sold
out:true. by Thread-0
[SaleMan1]Book10 sold out:true. by
Thread-0
[SaleMan1]Book11 sold out:true. by Thread-0
[SaleMan2]Book12 sold
out:true. by Thread-1
[SaleMan2]Book13 sold out:true. by
Thread-1
[SaleMan2]Book14 sold out:true. by Thread-1
[SaleMan2]Book15 sold
out:true. by Thread-1
[SaleMan2]Book16 sold out:true. by
Thread-1
[SaleMan2]Book17 sold out:true. by Thread-1
[SaleMan1]Book18 sold
out:true. by Thread-0
[SaleMan1]Book19 sold out:true. by Thread-0
線程的創(chuàng)建
創(chuàng)建新執(zhí)行線程有兩種方法。
方法一種方法是將類聲明為 Thread
的子類。該子類應(yīng)重寫 Thread 類的 run
方法。事實上類Thread本身也實現(xiàn)了接口Runnable,所以我們可以同過繼承Thread類實現(xiàn)線程體。
參考:
SellBookThread.java 與
CallSellBook.java
另一種方法是聲明實現(xiàn) Runnable
接口的類。該類然后實現(xiàn) run 方法。
參考:
SellBookRunnable.java 與
CallSellBook.java
線程的狀態(tài)
線程有四種狀態(tài):創(chuàng)建狀態(tài)(New),可運行狀態(tài)(Runnable),阻塞狀態(tài)(Blocked),死亡狀態(tài)(Dead)。
創(chuàng)建狀態(tài)(New):
當執(zhí)行完
Thread
t1 = new SellBookThread("SaleMan1",
bookList);
語句之后,則t1處于創(chuàng)建狀態(tài)(New)。此時t1并未真正運行。
可運行狀態(tài)(Runnable):
當Thread
t1被創(chuàng)建,并執(zhí)行完
t1.start();
語句之后,t1就處于可運行狀態(tài)(Runnable)。此時,系統(tǒng)為線程t1分配其所需的系統(tǒng)資源。并對t1加以調(diào)用(或者根據(jù)任務(wù)調(diào)度情況準備調(diào)用)。
阻塞狀態(tài)(Blocked):
由于以下原因:
1)
調(diào)用了sleep()方法;
2) 調(diào)用了suspend()方法(該方法已不推薦使用);
3) 為等待條件鎖,調(diào)用wait()方法等;
4)
輸入輸出,或消息發(fā)生阻塞;
使得線程處于阻塞狀態(tài)(Blocked)。處于該狀態(tài)的線程即使處理器空閑,也不會得到執(zhí)行。
死亡狀態(tài)(Dead):
死亡狀態(tài)(Dead)可以為自然死亡(線程運行完畢),或者調(diào)用了stop()方法(該方法已不推薦使用)。
線程的優(yōu)先級:
可以通過Thread類的
void setPriority(int
newPriority)
方法為線程設(shè)置優(yōu)先級。但是不能保證高優(yōu)先級的線程就會被先運行。
線程組:
可以通過
ThreadGroup group = new
ThreadGroup(groupName);
Thread t1 = new Thread(ThreadGroup g, Runnable
r1);
Thread t1 = new Thread(ThreadGroup g, Runnable
r2);
等方法把多個線程加到一個線程組里去,這樣可以通過ThreadGroup對這些線程進行某些統(tǒng)一操作,
例如:group.interrupt();中斷該組所有線程。
線程unchecked異常處理器:
可以通過:
public void static
Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler)
方法為所有線程指定一個unchecked異常處理器,該處理器必須實現(xiàn)UncaughtExceptionHandler接口。
線程同步:
線程同步指多個線程同時訪問某資源時,采用一系列的機制以保證同時最多只能一個線程訪問該資源。
線程同步是多線程中必須考慮和解決的問題,因為很可能發(fā)生多個線程同時訪問(主要是寫操作)同一資源,如果不進行線程同步,很可能會引起數(shù)據(jù)混亂,造成線程死鎖等問題。
使用synchronized同步線程。
在J2SE5.0之前,只能使用synchronized來同步線程。可以使用synchronized來同步代碼塊或者方法。
同步代碼塊例:
synchronized(欲同步的對象obj)
{需要同步的代碼塊}可以同步代碼塊。
參考:
SellBookThread.java
- privatevoid sellBook(Book book) {
- synchronized (book) {
- ...
- }
- }
private void sellBook(Book book) {
synchronized (book) {
...
}
}
該例synchronized (book)
表示若多個線程同時訪問時,只讓其中一個線程最先取得book對象,其它線程則阻塞直到代碼塊執(zhí)行完畢book對象被釋放后,其它線程才能取得該book對象繼續(xù)執(zhí)行。
很多情況下,可以使用synchronized
(this){...}來同步代碼塊。但需要注意的是,使用this作為同步對象的話,如果同一個類中存在多個synchronized
(this){...}代碼塊,其中任何一個synchronized(this)代碼塊處于被執(zhí)行狀態(tài),則其它線程對其他synchronized(this)代碼塊的訪問也會受到阻塞。
同步方法例:
- synchronizedprivatevoid sellBook(Book book) {
- ...
- }
synchronized private void sellBook(Book book) {
...
}
這種方法其實相當于
- privatevoid sellBook(Book book) {
- synchronized(this) {
- ...
- }
- }
private void sellBook(Book book) {
synchronized(this) {
...
}
}
由于默認采用this作為同步對象,所以當一個類中有多個synchronized方法時,同樣會存在以上問題:即如果有一個線程訪問其中某個synchronized方法時,直到該方法執(zhí)行完畢,其它線程對其它synchronized方法的訪問也將受到阻塞。
有關(guān)synchronized詳細說明我們將在其它文章中加以說明。
使用java.util.concurrent.locks.ReentrantLock和java.util.concurrent.locks.ReentrantReadWriteLock類同步線程。
J2SE5.0加入了ReentrantLock和ReentrantReadWriteLock可以對線程進行同步,這里舉一個最簡單的例子對其加以說明:
- class X {
- privatefinal ReentrantLock lock = new ReentrantLock();
- // ...
- publicvoid m() {
- lock.lock(); // block until condition holds
- try {
- // ... method body
- } finally {
- lock.unlock()
- }
- }
- }
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
其它J2SE5.0新導(dǎo)入的有關(guān)線程的相關(guān)接口/類:
java.util.concurrent.Future
Future接口可以保持/取得異步執(zhí)行的結(jié)果值
java.util.concurrent.Callable
類似于Runnable接口。但Runnable不能返回值,也不能拋出checked異常
java.util.concurrent.ExecutorService
該接口繼承了Executor接口。可以通過submit方法把Runnable,Callable對象轉(zhuǎn)換為Future
形式。
java.util.concurrent.FutureTask
該類實現(xiàn)了Runnable和Future接口。提供異步執(zhí)行的取消以及異步執(zhí)行結(jié)果的取得等功能。
java.util.concurrent.Executor
執(zhí)行指定的Runnable對象
java.util.concurrent.Executors
工具類。提供靜態(tài)方法可以創(chuàng)建Executor,ExecutorService,Callable等對象。可以通過newCachedThreadPool()等方法簡單創(chuàng)建線程池。