線程上

第十章 線程

10.1線程的概念:java

事實上,在單個程序內部是能夠在同一時刻進行多種運算的,這就是所謂的多進程(這與多任務的概念有類似之處)。、程序員

一個單獨的進程與順序程序類似,也有一個入口,一個出口,以及一個順序執行的序列。從概念上說,一個線程是一個程序內部的一個順序控制流。線程並非程序,它本身自己並不能運行,而必須在程序中運行。在一個程序中能夠實現多個進程,這些進程同時運行,可是多線程並不等於屢次啓動一個程序,操做系統也不會把每一個線程當作進程來對待。web

線程如進程的區別:編程

1:二者的顆粒度不一樣,是兩個不一樣層次上的概念。進程是由操做系統來管理的,而線程則是在一個程序(進程)內。安全

2:不一樣的的代碼,內部數據和狀態都是徹底獨立的,而一個程序內的多線程共享同一塊內存空間和同一組系統資源,有可能互相影響。網絡

3:線程自己的數據一般只有寄存器數據,以及一個程序執行時使用的堆棧,因此線程的切換負擔比進程切換有的要小。多線程

使用多線程具備的以下的優勢:併發

1:多線程編程簡單,效率高(能直接共享數據和資源,而多進程不能)ide

2:適合於開發服務程序(如web服務,聊天服務)工具

3:適合於開發有多種交互接口的程序(如聊天程序的客戶端,網路下載工具)

4:適合於有人機交互又有計算量的程序

5:減輕編寫交互頻繁,涉及面多的程序的困難(如監聽網絡接口)

6:程序的吞吐量會獲得改善

7:有多個處理器的系統,能夠併發運行不一樣的線程

10.2線程的創建

Java提供了類Java.lang.Thread來支持多線程編程,Thread類有如下的構造方法

Thread()

Thread(Runable target)

Thread(Runable target,String name)

Thread(String name)

Thread(ThreadGroup group,Rnuable target)

Thread(ThreadGroup group,Rnuable target,String name)

Thread(ThreadGroup group,String name)

參數target是線程執行的目標對象,即線程執行的代碼;group是線程所在的組;name是線程的名字

10.2.1採用繼承法建立線程

該方法比較簡單,主要是經過繼承java.lang.Thread,並覆蓋Thread類的run()方法來完成線程的建立.Thread類是一個具體的類不是抽象類,該類封裝了線程的行爲.要建立一個線程,程序員必須建立一個Thread的子類.Thread類中最重要的方法時run()start().

Run()方法必須進行重寫,把線程所要執行的代碼加入到這個方法中,也就是線程體.可是它必須通過start()方法來啓動線程.

public class MyThread extends Thread

{

// count變量用於統計打印的次數並共享變量

private static int count = 0;

public static void main(String[] args)

{

MyThread p = new MyThread("t1");

// 線程執行

p.start();

// 主線程main方法執行一個循環

for (int i = 0; i < 5; i++)

{

count++;

System.out.println(count + " :main");

}

}

// 構造方法

public MyThread(String name)

{

// 調用父類的構造方法

super(name);

}

@Override

public void run()

{

// 線程中必須有的run方法

for (int i = 0; i < 5; i++)

{

count++;

System.out.println(count + ":" + this.getName());

}

}

}

10.2.2 經過實現接口建立線程

該方法經過實現java.lang.Runnable接口的類來建立多線程.該接口定義了一個方法run(),因此必須的新類中實現它,可是Runnable接口中沒有任何對線程的支持,還必需要建立Thread類的實例

public class MyThread2 implements Runnable

{

public static void main(String[] args)

{

for (int i = 0; i < 5; i++)

{

new Thread(new MyThread2(i + 1)).start();

}

}

int count, number;

public MyThread2(int i)

{

this.number = i;

System.out.println("建立線程 " + this.number);

}

public void run()

{

while (true)

{

System.out.println("線程 " + this.number + ":計數 " + this.count);

if (++this.count == 6)

{

return;

}

}

}

}

10.3線程的生命週期及調度

10.3.1 線程的生命週期

線程是動態的,具備必定的生命週期,分別從建立,執行,堵塞直到死亡.在每個線程類中都定義了用於完成功能的run方法,這個方法稱爲線程體

1:線程的四個狀態

1.1:建立狀態:

當利用new關鍵字建立線程對象實例後,它僅僅做爲一個對象實例存在,JVM沒有爲其分配CPU時間片等線程資源

1.2:就緒狀態:

當處於建立狀態的線程中調用start方法將線程的狀態轉換爲就緒狀態.

1.3:堵塞狀態

堵塞指的是暫停一個線程的執行以等待某個條件發生(如某資源準備就緒),若線程處於堵塞狀態,調度機制不給它分配任何CPU時間,直接跳過它.

1.4:死亡狀態

當線程運行結束或者在調用線程對象的stop方法後線程將終止運行,JVM收回線程佔用的資源

10.3.2:線程調度和優先級

Java採用的是一種簡單,固定的調度法,即固定優先級調度(搶先式調度),Java將線程的優先級分爲10個等級,分別用110的數字表示.數字越大代表線程的級別越高.相應的,Thread類中定義了表示線程最高,最低,和普通優先級的常量MIN_PRIORITY,MAX_PRIORITY,NORMAL_PRIORITY,表明的優先級分別是1,10,5,當一個線程對象被建立時,其默認的優先級是5.

在應用程序中設置線程優先級的方法比較簡單,在建立線程對象後能夠調用線程對象的setPriority()方法該表線程的優先級,一樣能夠調用getPriority()來獲取當前線程的優先級.

public class TestThreadPriority extends Thread

{

public static void main(String[] args)

{

TestThreadPriority t1 = new TestThreadPriority("Thread1");

t1.setPriority(MIN_PRIORITY);

t1.start();

TestThreadPriority t2 = new TestThreadPriority("Thread2");

t2.setPriority(NORM_PRIORITY);

t2.start();

TestThreadPriority t3 = new TestThreadPriority("Thread3");

t3.setPriority(MAX_PRIORITY);

t3.start();

}

public TestThreadPriority(String name)

{

super(name);

}

@Override

public void run()

{

for (int i = 0; i < 3; i++)

{

System.out.println(this.getName() + " is running");

}

super.run();

}

}

10.4:線程互斥

在併發程序設計中已經被研究並獲得解決.對多線程共享的資源或數據稱爲臨界資源,而把每個線程中訪問臨界資源的那一段代碼稱爲臨界代碼.經過爲臨界帶買段設置信號燈,就能夠保證資源的完整性,從而安全地訪問共享資源.

爲了實現這種機制,Java語言提供瞭如下兩方面的支持

爲每一個對象設置了一個互斥鎖標記.該標記保證在任什麼時候候,只能有一個線程有該互斥鎖,其餘線程若是須要得到互斥鎖,必須等待當前擁有該鎖的線程將其釋放.該對象稱爲互斥對象.

爲了配合使用對象的互斥鎖,Java語言提供了保留字synchronized.其基本用法以下:

Synchronized(互斥對象){

臨界代碼

}

當一個線程執行到該行代碼時,首先檢測該互斥對象的互斥鎖.若是該互斥鎖沒有被佔用,則該線程將得到該互斥鎖,並執行臨界代碼,直到執行完畢並釋放互斥鎖;

能夠看出,任意一個對象均可以做爲信息燈,從而解決上面的問題,首先定義一個互斥對象類,做爲信號燈.因爲該對象只做爲信號量使用,因此並不須要爲它定義其餘方法.

public class AccountThread extends Thread

{

public static void main(String[] args)

{

Account account = new Account(100);

Semaphore semaphore = new Semaphore();

AccountThread at1 = new AccountThread(account, 1000, semaphore);

AccountThread at2 = new AccountThread(account, 0, semaphore);

at1.start();

at2.start();

}

Account account;

int delay;

Semaphore semaphore;

// 構造方法

public AccountThread(Account account, int delay, Semaphore semaphore)

{

this.account = account;

this.delay = delay;

this.semaphore = semaphore;

}

@Override

public void run()

{

synchronized (this.semaphore)

{

if (this.account.balance >= 100)

{

try

{

// 延遲

sleep(this.delay);

// 模擬取錢100

this.account.balance = this.account.balance - 100;

System.out.println("withdraw 100 successful!!!");

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

else

{

System.out.println("withdraw failed!!!");

}}}}

// 定義一個類,利用其對象做爲互斥信號燈

class Semaphore{}

相關文章
相關標籤/搜索