導航:首頁 > 編程知識 > 編程多線程序怎麼使用

編程多線程序怎麼使用

發布時間:2023-05-19 00:16:12

1. 如何學習java中的多線程

幾乎所有使用 AWT 或 Swing 編寫的畫圖程序都需要多線程。但多線程程序會造成許多困難,剛開始編程的開發者常常會發現他們被一些問題所折磨,例如不正確的程序行為或死鎖。

在本文中,我們將探討使用多線程時遇到的問題,並提出那些常見陷阱的解決方案。

線程是什麼?
一個程序或進程能夠包含多個線程,這些線程可以根據程序的代碼執行相應的指令。多線程看上去似乎在並行執行它們各自的工作,就像在一台計算機上運行著多個處理機一樣。在多處理機計算機上實現多線程時,它們確實可以並行工作。和進程不同的是,線程共享地址空間。也就是說,多個線程能夠讀寫相同的變數或數據結構。

編寫多線程程序時,你必須注意每個線程是否干擾了其他線程的工作。可以將程序看作一個辦公室,如果不需要共享辦公室資源或與其他人交流,所有職員就會獨立並行地工作。某個職員若要和其他人交談,當且僅當該職員在「聽」且他們兩說同樣的語言。此外,只有在復印機空閑且處於可用狀態(沒有僅完成一半的復印工作,沒有紙張阻塞等問題)時,職員才能夠使用它。在這篇文章中你將看到,在 Java 程序中互相協作的線程就好像是在一個組織良好的機構中工作的職員。

在多線程程序中,線程可以從准備就緒隊列中得到,並在可獲得的系統 CPU 上運行。操作系統可以將線程從處理器移到准備就緒隊列或阻塞隊列中,這種情況可以認為是處理器「掛起」了該線程。同樣,Java 虛擬機 (JVM) 也可以控制線程的移動??在協作或搶先模型中??從准備就緒隊列中將進程移到處理器中,於是該線程就可以開始執行它的程序代碼。

協作式線程模型允許線程自己決定什麼時候放棄處理器來等待其他的線程。程序開發員可以精確地決定某個線程何時會被其他線程掛起,允許它們與對方有效地合作。缺點在於某些惡意或是寫得不好的線程會消耗所有可獲得的 CPU 時間,導致其他線程「飢餓」。

在搶占式線程模型中,操作系統可以在任何時候打斷線程。通常會在它運行了一段時間(就是所謂的一個時間片)後才打斷它。這樣的結果自然是沒有線程能夠不公平地長時間霸佔處理器。然而,隨時可能打斷線程就會給程序開發員帶來其他麻煩。同樣使用辦公室的例子,假設某個職員搶在另一人前使用復印機,但列印工作在未完成的時候離開了,另一人接著使用復印機時,該復印機上可能就還有先前那名職員留下來的資料。搶占式線程模型要求線程正確共享資源,協作式模型卻要求線程共享執行時間。由於 JVM 規范並沒有特別規定線程模型,Java 開發員必須編寫可在兩種模型上正確運行的程序。在了解線程以及線程間通訊的一些方面之後,我們可以看到如何為這兩種模型設計程序。

線程和 Java 語言
為了使用 Java 語言創建線程,你可以生成一個 Thread 類(或其子類)的對象,並給這個對象發送 start() 消息。(程序可以向任何一個派生自 Runnable 介面的類對象發送 start() 消息。)每個線程動作的定義包含在該線程對象的 run() 方法中。run 方法就相當於傳統程序中的 main() 方法;線程會持續運行,直到 run() 返回為止,此時該線程便死了。

上鎖
大多數應用程序要求線程互相通信來同步它們的動作。在 Java 程序中最簡單實現同步的方法就是上鎖。為了防止同時訪問共享資源,線程在使用資源的前後可以給該資源上鎖和開鎖。假想給復印機上鎖,任一時刻只有一個職員擁有鑰匙。若沒有鑰匙就不能使用復印機。給共享變數上鎖就使得 Java 線程能夠快速方便地通信和同步。某個線程若給一個對象上了鎖,就可以知道沒有其他線程能夠訪問該對象。即使在搶占式模型中,其他線程也不能夠訪問此對象,直到上鎖的線程被喚醒、完成工作並開鎖。那些試圖訪問一個上鎖對象的線程通常會進入睡眠狀態,直到上鎖的線程開鎖。一旦鎖被打開,這些睡眠進程就會被喚醒並移到准備就緒隊列中。

在 Java 編程中,所有的對象都有鎖。線程可以使用 synchronized 關鍵字來獲得鎖。在任一時刻對於給定的類的實例,方法或同步的代碼塊只能被一個線程執行。這是因為代碼在執行之前要求獲得對象的鎖。繼續我們關於復印機的比喻,為了避免復印沖突,我們可以簡單地對復印資源實行同步。如同下列的代碼例子,任一時刻只允許一位職員使用復印資源。通過使用方法(在 Copier 對象中)來修改復印機狀態。這個方法就是同步方法。只有一個線程能夠執行一個 Copier 對象中同步代碼,因此那些需要使用 Copier 對象的職員就必須排隊等候。

class CopyMachine {
public synchronized void makeCopies(Document d, int nCopies) {
//only one thread executes this at a time
}
public void loadPaper() {
//multiple threads could access this at once!
synchronized(this) {
//only one thread accesses this at a time
//feel free to use shared resources, overwrite members, etc.
}
}
}

Fine-grain 鎖
在對象級使用鎖通常是一種比較粗糙的方法。為什麼要將整個對象都上鎖,而不允許其他線程短暫地使用對象中其他同步方法來訪問共享資源?如果一個對象擁有多個資源,就不需要只為了讓一個線程使用其中一部分資源,就將所有線程都鎖在外面。由於每個對象都有鎖,可以如下所示使用虛擬對象來上鎖:

class FineGrainLock {
MyMemberClass x, y;
Object xlock = new Object(), ylock = new Object();
public void foo() {
synchronized(xlock) {
//access x here
}
//do something here - but don�0�7t use shared resources
synchronized(ylock) {
//access y here
}
}
public void bar() {
synchronized(this) {
//access both x and y here
}
//do something here - but don�0�7t use shared resources
}
}

若為了在方法級上同步,不能將整個方法聲明為 synchronized 關鍵字。它們使用的是成員鎖,而不是 synchronized 方法能夠獲得的對象級鎖。

2. Java多線程編程

作者 natrium 一 理解多線程多線程是這樣一種機制 它允許在程序中並發執行多個指令流 每個指令流都稱為一個線程 彼此間互相獨立 線程又稱為輕量級進程 它和進程一樣擁有獨立的執行控制 由操作系統負責調度 區別在於線程沒有獨立的存儲空間 而是和所屬進程中的其它線程共享一個存儲空間 這使得線程間的通信遠較進程簡單 多個線程的執行梁卜是並發的 也就是在邏輯上 同時 而不管是否是物理上的 同時 如果系統只有一個CPU 那麼真正的 同時 是不可能的 但是由於CPU的速度非常快 用戶感覺不到其中的區別 因此我們也不用關心它 只需要設想各個線程是同時執行即可 多線程和傳統的單線程在程序設計上最大的區別在於 由於各個線程的控制流彼此獨立 使得各個線程之間的代碼是亂序執行的 由此帶來的線程調度 同步等問題 將在以後探討 二 在Java中實現多線程我們不妨設想 為了創建一個新的線程 我們需要做些什麼?很顯然 我們必須指明這個線程所要執行的代碼 而這就是在Java中實現多線程我們所需要做的一切!真是神奇!Java是如何做到這一點的?通過類!作為一個完全面向對象的語言 Java提供了類 java lang Thread 來方便多線程編程 這個類提供了大量的方法來方便我們控制自己的各個線程 我們以後的討論都將圍繞這個類進行 那麼如何提供給 Java 我們要線程執行的代碼呢?讓我們來看一看 Thread 類 Thread 類最重要的方法是 run() 它為Thread 類的方法 start() 所調用 提供我們的線程所要執行的代碼 為了指定我們自己的代碼 只需要覆蓋它!方法一 繼承 Thread 類 覆蓋方法 run() 我們在創建的 Thread 類的子類中重寫 run() 加入線程所要執行的代碼即陵早可 下面是一個例子 public class MyThread extends Thread {int count= number;public MyThread(int num) {number = num;System out println( 創建線程 + number);}public void run() {while(true) {System out println( 線程 + number + :計數 + count);if(++count== ) return;}}public static void main(String args[]) {for(int i = ; i < 5; i++) new MyThread(i+1).start();}}這種方法簡單明了,符合大家的習慣,但是,它也有一個很大的缺點,那就是如果我們的類已經從一個類繼承(如小程序必須繼承自 Applet 類),則無法再繼承 Thread 類,這時如果我們又不想建立一個新的類,應該怎麼辦呢?我們不妨來探索一種新的方法:我們不創建 Thread 類的子類,而是直接使用它,那麼我們只能將我們的方法作為參數傳遞給 Thread 類的實例,有點類似回調函數。.WINgWIT.但是 Java 沒有指針,我們只能傳遞一個包含這個方法的類的實例。那麼如何限制這個類必須包含這一方法呢?當然是使用介面!(雖然抽象類也可滿足,但是需要繼承,而我們之所以要採用這種新方法,不就是為了避免繼承帶來的限制嗎?)Java 提供了介面 java.lang.Runnable 來支持這種方法。方法二:實現 Runnable 介面Runnable 介面只有一個方法 run(),我們聲明自己的類實現 Runnable 介面並提供尺渣雀這一方法,將我們的線程代碼寫入其中,就完成了這一部分的任務。但是 Runnable 介面並沒有任何對線程的支持,我們還必須創建 Thread 類的實例,這一點通過 Thread 類的構造函數public Thread(Runnable target);來實現。下面是一個例子:public class MyThread implements Runnable {int count= 1, number;public MyThread(int num) {number = num;System.out.println("創建線程 " + number);}public void run() {while(true) {System.out.println("線程 " + number + ":計數 " + count);if(++count== 6) return;} }public static void main(String args[]) {for(int i = 0; i < 5; i++) new Thread(new MyThread(i+1)).start();}}嚴格地說,創建 Thread 子類的實例也是可行的,但是必須注意的是,該子類必須沒有覆蓋 Thread 類的 run 方法,否則該線程執行的將是子類的 run 方法,而不是我們用以實現Runnable 介面的類的 run 方法,對此大家不妨試驗一下。使用 Runnable 介面來實現多線程使得我們能夠在一個類中包容所有的代碼,有利於封裝,它的缺點在於,我們只能使用一套代碼,若想創建多個線程並使各個線程執行不同的代碼,則仍必須額外創建類,如果這樣的話,在大多數情況下也許還不如直接用多個類分別繼承 Thread 來得緊湊。綜上所述,兩種方法各有千秋,大家可以靈活運用。下面讓我們一起來研究一下多線程使用中的一些問題。三:線程的四種狀態1. 新狀態:線程已被創建但尚未執行(start() 尚未被調用)。2. 可執行狀態:線程可以執行,雖然不一定正在執行。CPU 時間隨時可能被分配給該線程,從而使得它執行。3. 死亡狀態:正常情況下 run() 返回使得線程死亡。調用 stop()或 destroy() 亦有同樣效果,但是不被推薦,前者會產生異常,後者是強制終止,不會釋放鎖。4. 阻塞狀態:線程不會被分配 CPU 時間,無法執行。四:線程的優先順序 線程的優先順序代表該線程的重要程度,當有多個線程同時處於可執行狀態並等待獲得 CPU 時間時,線程調度系統根據各個線程的優先順序來決定給誰分配 CPU 時間,優先順序高的線程有更大的機會獲得 CPU 時間,優先順序低的線程也不是沒有機會,只是機會要小一些罷了。你可以調用 Thread 類的方法 getPriority() 和 setPriority()來存取線程的優先順序,線程的優先順序界於1(MIN_PRIORITY)和10(MAX_PRIORITY)之間,預設是5(NORM_PRIORITY)。五:線程的同步由於同一進程的多個線程共享同一片存儲空間,在帶來方便的同時,也帶來了訪問沖突這個嚴重的問題。Java語言提供了專門機制以解決這種沖突,有效避免了同一個數據對象被多個線程同時訪問。由於我們可以通過 private 關鍵字來保證數據對象只能被方法訪問,所以我們只需針對方法提出一套機制,這套機制就是 synchronized 關鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。1. synchronized 方法:通過在方法聲明中加入 synchronized關鍵字來聲明 synchronized 方法。如:public synchronized void accessVal(int newVal);synchronized 方法控制對類成員變數的訪問:每個類實例對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的類實例的鎖方能執行,否則所屬線程阻塞,方法一旦執行,就獨占該鎖,直到從該方法返回時才將鎖釋放,此後被阻塞的線程方能獲得該鎖,重新進入可執行狀態。這種機制確保了同一時刻對於每一個類實例,其所有聲明為 synchronized 的成員函數中至多隻有一個處於可執行狀態(因為至多隻有一個能夠獲得該類實例對應的鎖),從而有效避免了類成員變數的訪問沖突(只要所有可能訪問類成員變數的方法均被聲明為 synchronized)。在 Java 中,不光是類實例,每一個類也對應一把鎖,這樣我們也可將類的靜態成員函數聲明為 synchronized ,以控制其對類的靜態成員變數的訪問。synchronized 方法的缺陷:若將一個大的方法聲明為synchronized 將會大大影響效率,典型地,若將線程類的方法 run() 聲明為 synchronized ,由於在線程的整個生命期內它一直在運行,因此將導致它對本類任何 synchronized 方法的調用都永遠不會成功。當然我們可以通過將訪問類成員變數的代碼放到專門的方法中,將其聲明為 synchronized ,並在主方法中調用來解決這一問題,但是 Java 為我們提供了更好的解決辦法,那就是 synchronized 塊。2. synchronized 塊:通過 synchronized關鍵字來聲明synchronized 塊。語法如下: synchronized(syncObject) {//允許訪問控制的代碼}synchronized 塊是這樣一個代碼塊,其中的代碼必須獲得對象 syncObject (如前所述,可以是類實例或類)的鎖方能執行,具體機制同前所述。由於可以針對任意代碼塊,且可任意指定上鎖的對象,故靈活性較高。六:線程的阻塞為了解決對共享存儲區的訪問沖突,Java 引入了同步機制,現在讓我們來考察多個線程對共享資源的訪問,顯然同步機制已經不夠了,因為在任意時刻所要求的資源不一定已經准備好了被訪問,反過來,同一時刻准備好了的資源也可能不止一個。為了解決這種情況下的訪問控制問題,Java 引入了對阻塞機制的支持。阻塞指的是暫停一個線程的執行以等待某個條件發生(如某資源就緒),學過操作系統的同學對它一定已經很熟悉了。Java 提供了大量方法來支持阻塞,下面讓我們逐一分析。1. sleep() 方法:sleep() 允許 指定以毫秒為單位的一段時間作為參數,它使得線程在指定的時間內進入阻塞狀態,不能得到CPU 時間,指定的時間一過,線程重新進入可執行狀態。典型地,sleep() 被用在等待某個資源就緒的情形:測試發現條件不滿足後,讓線程阻塞一段時間後重新測試,直到條件滿足為止。2. suspend() 和 resume() 方法:兩個方法配套使用,suspend()使得線程進入阻塞狀態,並且不會自動恢復,必須其對應的resume() 被調用,才能使得線程重新進入可執行狀態。典型地,suspend() 和 resume() 被用在等待另一個線程產生的結果的情形:測試發現結果還沒有產生後,讓線程阻塞,另一個線程產生了結果後 lishixin/Article/program/Java/gj/201311/27622

3. 多線程編程怎麼回事啊

每個正在系統上運行的程序都是一個進程。每個進程包含一到多個線程。進程也可能是整個程序或者是部分程序的動態執行。線程是一組指令的集合,或者是程序的特殊段,它可以在程序里獨立執行。也可以把它理解為代碼運行的上下文。所以線程基本上是輕量級的進程,它負責在單個程序里執行多任務。通常由操作系統負責多個線程的調度和執行。

什麼是多線程?

多線程是為了使得多個線程並行的工作以完成多項任務,以提高系統的效率。線程是在同一時間需要完成多項任務的時候被實現的。

使用線程的好處有以下幾點:

·使用線程可以把占據長時間的程序中的任務放到後台去處理

·用戶界面可以更加吸引人,這樣比如用戶點擊了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度

·程序的運行速度可能加快

·在一些等待的任務實現上如用戶輸入、文件讀寫和網路收發數據等,線程就比較有用了。在這種情況下我們可以釋放一些珍貴的資源如內存佔用等等。

還有其他很多使用多線程的好處,這里就不一一說明了。

一些線程模型的背景

我們可以重點討論一下在Win32環境中常用的一些模型。

·單線程模型

在這種線程模型中,一個進程中只能有一個線程,剩下的進程必須等待當前的線程執行完。這種模型的缺點在於系統完成一個很小的任務都必須佔用很長的時間。

·塊線程模型(單線程多塊模型STA)

這種模型里,一個程序里可能會包含多個執行的線程。在這里,每個線程被分為進程里一個單獨的塊。每個進程可以含有多個塊,可以共享多個塊中的數據。程序規定了每個塊中線程的執行時間。所有的請求通過Windows消息隊列進行串列化,這樣保證了每個時刻只能訪問一個塊,因而只有一個單獨的進程可以在某一個時刻得到執行。這種模型比單線程模型的好處在於,可以響應同一時刻的多個用戶請求的任務而不只是單個用戶請求。但它的性能還不是很好,因為它使用了串列化的線程模型,任務是一個接一個得到執行的。

·多線程塊模型(自由線程塊模型)

多線程塊模型(MTA)在每個進程里只有一個塊而不是多個塊。這單個塊控制著多個線程而不是單個線程。這里不需要消息隊列,因為所有的線程都是相同的塊的一個部分,並且可以共享。這樣的程序比單線程模型和STA的執行速度都要塊,因為降低了系統的負載,因而可以優化來減少系統idle的時間。這些應用程序一般比較復雜,因為程序員必須提供線程同步以保證線程不會並發的請求相同的資源,因而導致競爭情況的發生。這里有必要提供一個鎖機制。但是這樣也許會導致系統死鎖的發生。

4. 誰知道多線程編程

主要內容:

1, 工作者線程

2, 用戶界面線程

3, 同步

線程被分為工作者線程和用戶用戶界面線程。用戶界面的線程的特點是擁有單獨的消息隊列,可以具有自己的窗口界面,能夠對用戶輸入和事件作出反應。

可以用以下方法建立一個工作者線程。

UINT MyThreadProc(LPVOID pParam)

{



}

AfxBeginThread(MyThread,..);

它有六個參數,第一個為控制函數,第二個為啟動線程時傳給控制函數的入口參數,當前線程的優先順序,當前線程的棧的大小,當前線程的創建狀態,安全屬性,後四個有默認值。

用戶界面線程:

首先利用應用程序向導建立單文檔程序Thread,再建立Thread1 : public CWinThread,

Frame1 : public CFrameWnd,可以用Ctrl+w建立這兩個新類。

在CThreadApp中加一個指針Thread1* pThread1,在BOOL CThreadApp::InitInstance()

中進行初始化:

pThread1 = new Thread1();

pThread1->CreateThread();

將Thread1的構造函數改成公有。

在Thread1中加一個指針Frame1* m_pWnd,然後初始化。

BOOL Thread1::InitInstance()

{

m_pWnd = new Frame1();

return TRUE;

}

把Frame1的構造函數改成公有,在Thread.h中包含#include "Frame1.h"。

在資源編輯器中編輯一個菜單IDR_MENU,它有一個菜單項ID_BEGIN。

Frame1::Frame1()

{

Create(NULL,"Demo");

ShowWindow(SW_SHOW);

UpdateWindow();

CMenu menu;//可以用局部變數,因為以後不會用到它了,加菜單。

menu.LoadMenu(IDR_MENU);

SetMenu(&menu);

}

同步

多線程的一個難點是各線程間的協調。同樣的方法在CThreadApp中再開一個線程。

BOOL CThreadApp::InitInstance()

{

。。。。。。

pThread1 = new Thread1();

pThread1->CreateThread();

pThread2 = new Thread1();

pThread2->CreateThread();

。。。。。。

}

為IDR_MENU中的菜單在Frame1中設立響應函數,方法也是Ctrl+w打開類向導。並在Frame1中定義一個全局整形變數n,初始值為0.

HANDLE handle=CreateSemaphore(NULL,0,1,"he");

WaitForSingleObject(handle,10000);

CString str;

n++;

str.Format("第%d次工作",n);

MessageBox(str);

ReleaseSemaphore(handle,1,NULL);

當你點擊Frame1的菜單時,會彈出一個對話框,暫時不要點 確定,點擊另一個線程的菜單,暫不會彈出對話框,確定剛才的對話框,另一個線程的對話框也彈出來了。

這個同步的方法稱為信號量。它允許有限的線程存取某個共享的系統資源,採用計數器來實現信號量。

HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpa,LONG cSemInitial,LONG cSemMax,LPTSR lpszSemName);

第一個參數來指明所創建的對象是否可以被其子進程繼承。如果你希望在所有的子進程之間共享這個信號量,可以把它的成員bInheritHandle設為true,也可以直接設為NULL來使用默認的安全設置第二個參數是還可以讓幾個線程使用,第三個參數是最多可以讓幾個線程使用。

最後參數是信號量的名字,在其它的進程中調用CreateSemapphore()或OpenSemaphore()時使用這個字元串作為參數之一就可以得到信號量的句柄。

ReleaseSemaphore(HANDLE hSemaphore, LONG cRelease,LPLONG plPrev)

5. Java多線程程序設計詳細解析


一、理解多線程
多線程是這樣一種機制,它允許在程序中並發執行多個指令流,每個指令流都稱為一個線程,彼此間互相獨立。
線程又稱為輕量級進程,它和進程一樣擁有獨立的執行控制,由操作系統負責調度,區別在於線程沒有獨立的存儲空間,而是和所屬進程中的其它線程共享一個存儲空間,這使得線程間的通信遠較進程簡單。
多個線程的執行是並發的,也就是在邏輯上「同時」,而不管是否是物理上的「同時」。如果系統只有一個CPU,那麼真正的「同時」是不可能的,但是由於CPU的速度非常快,用戶感覺不到其中的區別,因此我們也不用關心它,只需要設想各個線程是同時執行即可。
多線程和傳統的單線程在程序設計上最大的區別在於,由於各個線程的控制流彼此獨立,使得各個線程之間的代碼是亂序執行的,由此帶來的線程調度,同步等問題,將在以後探討。
二、在Java中實現多線凱液慎程
我們不妨設想,為了創建一個新的線程,我們需要做些什麼?很顯然,我們必須指明這個線程所要執行的代碼,而這就是在Java中實現多線程我們所需要做的一切!
真是神奇!Java是如何做到這一點的?通過類!作為一個完全面向對象的語言,Java提供了類java.lang.Thread來方便多線程編程,這個類提供了大量的方法來方便我們控制自己的各個線程,我們以後的討論都將圍繞這個類進行。
那麼如何提供給 Java 我們要線程執行的代碼呢?讓我們來看一看 Thread 類。Thread 類最重要的方法是run(),它為Thread類的方法start()所調用,提供我們的線程所要執行的代碼。為了指定我們自己的代碼,只需要覆蓋它!
方法一:繼承 Thread 類,覆蓋方法 run(),我們在創建的 Thread 類的子類中重寫 run() ,加入線程所要執行的代碼即可。下面是一個例子:
public class MyThread extends Thread
{
int count= 1, number;
public MyThread(int num)
{
number = num;
System.out.println
("創建線程 " + number);
}
public void run() {
while(true) {
System.out.println
("線程 " + number + ":計數 " + count);
if(++count== 6) return;
}
}
public static void main(String args[])
{
for(int i = 0;
i 〈 5; i++) new MyThread(i+1).start();
}
}
這種方法簡單明了,符合大家的習慣,但是,它也有一個很大的缺點,那就是如果我們的類已經從一個類繼承(如小程序必須繼承自 Applet 類),則無法再繼承 Thread 類,這時如果我們又不想建立一個新的類,應該怎麼辦呢?
我們不妨來探索一種新的方法:我們不創建Thread類的子類,而是直接使用它,那麼我們只能將我們的方法作為參數傳遞給 Thread 類的實例,有點類似回調函數。但是 Java 沒有指針,我們只能傳遞一個包含這個方法的類的實例。
那麼如何限制這個類盯敬必須包含這一方法呢?當然是使用介面!(雖然抽象類也可滿足,但是需要繼承,而我們之所以要採用這種新方法,不就是為了避免繼承帶來的限制嗎?)
Java 提供了介面 java.lang.Runnable 來支持這種方法。
方法二:實現 Runnable 介面
Runnable介面只有一個方法run(),我們聲明自己的類實現Runnable介面並提供這一方法,將我們的線程代碼寫入其中,就完成了這一部分的任務。但是Runnable介面並沒有任何對線程的支持,我們還必須創建Thread類的實例,這一點通過Thread類的構造函數public Thread(Runnable target);來實現。下面埋禪是一個例子:
public class MyThread implements Runnable
{
int count= 1, number;
public MyThread(int num)
{
number = num;
System.out.println("創建線程 " + number);
}
public void run()
{
while(true)
{
System.out.println
("線程 " + number + ":計數 " + count);
if(++count== 6) return;
}
}
public static void main(String args[])
{
for(int i = 0; i 〈 5;
i++) new Thread(new MyThread(i+1)).start();
}
}
嚴格地說,創建Thread子類的實例也是可行的,但是必須注意的是,該子類必須沒有覆蓋 Thread 類的 run 方法,否則該線程執行的將是子類的 run 方法,而不是我們用以實現Runnable 介面的類的 run 方法,對此大家不妨試驗一下。
使用 Runnable 介面來實現多線程使得我們能夠在一個類中包容所有的代碼,有利於封裝,它的缺點在於,我們只能使用一套代碼,若想創建多個線程並使各個線程執行不同的代碼,則仍必須額外創建類,如果這樣的話,在大多數情況下也許還不如直接用多個類分別繼承 Thread 來得緊湊。
綜上所述,兩種方法各有千秋,大家可以靈活運用。
下面讓我們一起來研究一下多線程使用中的一些問題。
三、線程的四種狀態
1. 新狀態:線程已被創建但尚未執行(start() 尚未被調用)。
2. 可執行狀態:線程可以執行,雖然不一定正在執行。CPU 時間隨時可能被分配給該線程,從而使得它執行。
3. 死亡狀態:正常情況下 run() 返回使得線程死亡。調用 stop()或 destroy() 亦有同樣效果,但是不被推薦,前者會產生異常,後者是強制終止,不會釋放鎖。
4. 阻塞狀態:線程不會被分配 CPU 時間,無法執行。
四、線程的優先順序
線程的優先順序代表該線程的重要程度,當有多個線程同時處於可執行狀態並等待獲得 CPU 時間時,線程調度系統根據各個線程的優先順序來決定給誰分配 CPU 時間,優先順序高的線程有更大的機會獲得 CPU 時間,優先順序低的線程也不是沒有機會,只是機會要小一些罷了。
你可以調用 Thread 類的方法 getPriority() 和 setPriority()來存取線程的優先順序,線程的優先順序界於1(MIN_PRIORITY)和10(MAX_PRIORITY)之間,預設是5(NORM_PRIORITY)。
五、線程的同步
由於同一進程的多個線程共享同一片存儲空間,在帶來方便的同時,也帶來了訪問沖突這個嚴重的問題。Java語言提供了專門機制以解決這種沖突,有效避免了同一個數據對象被多個線程同時訪問。
由於我們可以通過 private 關鍵字來保證數據對象只能被方法訪問,所以我們只需針對方法提出一套機制,這套機制就是 synchronized 關鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。
1. synchronized 方法:通過在方法聲明中加入 synchronized關鍵字來聲明 synchronized 方法。如:
public synchronized void accessVal(int newVal);
synchronized 方法控制對類成員變數的訪問:每個類實例對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的類實例的鎖方能執行,否則所屬線程阻塞,方法一旦執行,就獨占該鎖,直到從該方法返回時才將鎖釋放,此後被阻塞的線程方能獲得該鎖,重新進入可執行狀態。
這種機制確保了同一時刻對於每一個類實例,其所有聲明為 synchronized 的成員函數中至多隻有一個處於可執行狀態(因為至多隻有一個能夠獲得該類實例對應的鎖),從而有效避免了類成員變數的訪問沖突(只要所有可能訪問類成員變數的方法均被聲明為 synchronized)。
在 Java 中,不光是類實例,每一個類也對應一把鎖,這樣我們也可將類的靜態成員函數聲明為 synchronized ,以控制其對類的靜態成員變數的訪問。
synchronized 方法的缺陷:若將一個大的方法聲明為synchronized 將會大大影響效率,典型地,若將線程類的方法 run() 聲明為 synchronized ,由於在線程的整個生命期內它一直在運行,因此將導致它對本類任何 synchronized 方法的調用都永遠不會成功。當然我們可以通過將訪問類成員變數的代碼放到專門的方法中,將其聲明為 synchronized ,並在主方法中調用來解決這一問題,但是 Java 為我們提供了更好的解決辦法,那就是 synchronized 塊。
2. synchronized 塊:通過 synchronized關鍵字來聲明synchronized 塊。語法如下:
synchronized(syncObject)
{
//允許訪問控制的代碼
}
#p#副標題#e#
synchronized 塊是這樣一個代碼塊,其中的代碼必須獲得對象 syncObject (如前所述,可以是類實例或類)的鎖方能執行,具體機制同前所述。由於可以針對任意代碼塊,且可任意指定上鎖的對象,故靈活性較高。
六、線程的阻塞為了解決對共享存儲區的訪問沖突,Java 引入了同步機制,現在讓我們來考察多個線程對共享資源的訪問,顯然同步機制已經不夠了,因為在任意時刻所要求的資源不一定已經准備好了被訪問,反過來,同一時刻准備好了的資源也可能不止一個。為了解決這種情況下的訪問控制問題,Java 引入了對阻塞機制的支持。
阻塞指的是暫停一個線程的執行以等待某個條件發生(如某資源就緒),學過操作系統的同學對它一定已經很熟悉了。Java 提供了大量方法來支持阻塞,下面讓我們逐一分析。
1. sleep() 方法:sleep() 允許 指定以毫秒為單位的一段時間作為參數,它使得線程在指定的時間內進入阻塞狀態,不能得到CPU 時間,指定的時間一過,線程重新進入可執行狀態。典型地,sleep() 被用在等待某個資源就緒的情形:測試發現條件不滿足後,讓線程阻塞一段時間後重新測試,直到條件滿足為止。
2. suspend() 和 resume() 方法:兩個方法配套使用,suspend()使得線程進入阻塞狀態,並且不會自動恢復,必須其對應的resume() 被調用,才能使得線程重新進入可執行狀態。典型地,suspend() 和 resume() 被用在等待另一個線程產生的結果的情形:測試發現結果還沒有產生後,讓線程阻塞,另一個線程產生了結果後,調用 resume() 使其恢復。
3. yield() 方法:yield() 使得線程放棄當前分得的 CPU 時間,但是不使線程阻塞,即線程仍處於可執行狀態,隨時可能再次分得 CPU 時間。調用 yield() 的效果等價於調度程序認為該線程已執行了足夠的時間從而轉到另一個線程。
4. wait() 和 notify() 方法:兩個方法配套使用,wait() 使得線程進入阻塞狀態,它有兩種形式,一種允許 指定以毫秒為單位的一段時間作為參數,另一種沒有參數,前者當對應的 notify() 被調用或者超出指定時間時線程重新進入可執行狀態,後者則必須對應的 notify() 被調用。
初看起來它們與 suspend() 和 resume() 方法對沒有什麼分別,但是事實上它們是截然不同的。區別的核心在於,前面敘述的所有方法,阻塞時都不會釋放佔用的鎖(如果佔用了的話),而這一對方法則相反。
上述的核心區別導致了一系列的細節上的區別。
首先,前面敘述的所有方法都隸屬於 Thread 類,但是這一對卻直接隸屬於 Object 類,也就是說,所有對象都擁有這一對方法。初看起來這十分不可思議,但是實際上卻是很自然的,因為這一對方法阻塞時要釋放佔用的鎖,而鎖是任何對象都具有的,調用任意對象的 wait() 方法導致線程阻塞,並且該對象上的鎖被釋放。
而調用 任意對象的notify()方法則導致因調用該對象的 wait() 方法而阻塞的線程中隨機選擇的一個解除阻塞(但要等到獲得鎖後才真正可執行)。
其次,前面敘述的所有方法都可在任何位置調用,但是這一對方法卻必須在 synchronized 方法或塊中調用,理由也很簡單,只有在synchronized 方法或塊中當前線程才佔有鎖,才有鎖可以釋放。
同樣的道理,調用這一對方法的對象上的鎖必須為當前線程所擁有,這樣才有鎖可以釋放。因此,這一對方法調用必須放置在這樣的 synchronized 方法或塊中,該方法或塊的上鎖對象就是調用這一對方法的對象。若不滿足這一條件,則程序雖然仍能編譯,但在運行時會出現IllegalMonitorStateException 異常。
wait() 和 notify() 方法的上述特性決定了它們經常和synchronized 方法或塊一起使用,將它們和操作系統的進程間通信機製作一個比較就會發現它們的相似性:synchronized方法或塊提供了類似於操作系統原語的功能,它們的執行不會受到多線程機制的干擾,而這一對方法則相當於 block 和wakeup 原語(這一對方法均聲明為 synchronized)。
它們的結合使得我們可以實現操作系統上一系列精妙的進程間通信的演算法(如信號量演算法),並用於解決各種復雜的線程間通信問題。
關於 wait() 和 notify() 方法最後再說明兩點:
第一:調用 notify() 方法導致解除阻塞的線程是從因調用該對象的 wait() 方法而阻塞的線程中隨機選取的,我們無法預料哪一個線程將會被選擇,所以編程時要特別小心,避免因這種不確定性而產生問題。
第二:除了 notify(),還有一個方法 notifyAll() 也可起到類似作用,唯一的區別在於,調用 notifyAll() 方法將把因調用該對象的 wait() 方法而阻塞的所有線程一次性全部解除阻塞。當然,只有獲得鎖的那一個線程才能進入可執行狀態。
談到阻塞,就不能不談一談死鎖,略一分析就能發現,suspend() 方法和不指定超時期限的 wait() 方法的調用都可能產生死鎖。遺憾的是,Java 並不在語言級別上支持死鎖的避免,我們在編程中必須小心地避免死鎖。
以上我們對 Java 中實現線程阻塞的各種方法作了一番分析,我們重點分析了 wait() 和 notify()方法,因為它們的功能最強大,使用也最靈活,但是這也導致了它們的效率較低,較容易出錯。實際使用中我們應該靈活使用各種方法,以便更好地達到我們的目的。
七、守護線程
守護線程是一類特殊的線程,它和普通線程的區別在於它並不是應用程序的核心部分,當一個應用程序的所有非守護線程終止運行時,即使仍然有守護線程在運行,應用程序也將終止,反之,只要有一個非守護線程在運行,應用程序就不會終止。守護線程一般被用於在後台為其它線程提供服務。
可以通過調用方法 isDaemon() 來判斷一個線程是否是守護線程,也可以調用方法 setDaemon() 來將一個線程設為守護線程。
八、線程組
線程組是一個 Java 特有的概念,在 Java 中,線程組是類ThreadGroup 的對象,每個線程都隸屬於唯一一個線程組,這個線程組在線程創建時指定並在線程的整個生命期內都不能更改。
你可以通過調用包含 ThreadGroup 類型參數的 Thread 類構造函數來指定線程屬的線程組,若沒有指定,則線程預設地隸屬於名為 system 的系統線程組。
在 Java 中,除了預建的系統線程組外,所有線程組都必須顯式創建。在 Java 中,除系統線程組外的每個線程組又隸屬於另一個線程組,你可以在創建線程組時指定其所隸屬的線程組,若沒有指定,則預設地隸屬於系統線程組。這樣,所有線程組組成了一棵以系統線程組為根的樹。
Java 允許我們對一個線程組中的所有線程同時進行操作,比如我們可以通過調用線程組的相應方法來設置其中所有線程的優先順序,也可以啟動或阻塞其中的所有線程。
Java 的線程組機制的另一個重要作用是線程安全。線程組機制允許我們通過分組來區分有不同安全特性的線程,對不同組的線程進行不同的處理,還可以通過線程組的分層結構來支持不對等安全措施的採用。
Java 的 ThreadGroup 類提供了大量的方法來方便我們對線程組樹中的每一個線程組以及線程組中的每一個線程進行操作。
九、總結
在本文中,我們講述了 Java 多線程編程的方方面面,包括創建線程,以及對多個線程進行調度、管理。我們深刻認識到了多線程編程的復雜性,以及線程切換開銷帶來的多線程程序的低效性,這也促使我們認真地思考一個問題:我們是否需要多線程?何時需要多線程?
多線程的核心在於多個代碼塊並發執行,本質特點在於各代碼塊之間的代碼是亂序執行的。我們的程序是否需要多線程,就是要看這是否也是它的內在特點。
假如我們的程序根本不要求多個代碼塊並發執行,那自然不需要使用多線程;假如我們的程序雖然要求多個代碼塊並發執行,但是卻不要求亂序,則我們完全可以用一個循環來簡單高效地實現,也不需要使用多線程;只有當它完全符合多線程的特點時,多線程機制對線程間通信和線程管理的強大支持才能有用武之地,這時使用多線程才是值得的。
#p#副標題#e#

6. 如何用c++builder 編寫多線程

摘 要:本文簡單介紹了Windows環境下進行多線程編程的意義,重點討論了C++Builder環境下開發多線程應用程序這一問題,並通過實現生產者-消費者問題,幫我們更好地理解同步概念及其實現方法。
關鍵詞:多線程;同步;生產者-消費者;C++Builder
線程之可行性
在很多情況下,可能需要為程序創建線程。這里給出其中一些可能性:
(1)如果創建的是一個多文檔介面(Multiple Document Interface,MDI)程序,那麼為每個窗口分配一個線程就顯得十分重要了,例如,對於一個通過多個Modem同時連接到多個主機的MDI通信程序而言,如果每個窗口都有它自己的線程來和一個主機通信,那麼整個事情就簡化很多。
(2)如果使用的是一台有多個處理器的機器,並希望充分利用所有可能獲得的CPU資源,那麼就需要將應用程序分解成多個線程。Windows2000中CPU的劃分單位為線程。因此,如果程序只包含一個線程,那麼,默認環境下該程序只能使用其中一個CPU。但是,如果將此程序劃分為多個線程,那麼Windows2000就可以在不同的CPU上運行各個線程。
(3)在後台運行的某些任務的同時,要求用戶還可以繼續使用應用程序進行工作。利用線程很容易實現這點。例如:可以將一些冗長的重算、頁面格式化操作、文件的讀寫等活動都放在單獨的線程中,使其在後台運行,而不會對用戶造成影響。
同步
撰寫多線程程序的一個最具挑戰性的問題就是:如何讓一個線程和另一個線程合作。這引出了一個非常重要的問題:同步。所謂同步是指進程、線程間相互通信時避免破壞各自數據的能力。Windows環境下的同步問題是由Win32系統的CPU時間片分配方式引起的。雖然在某一時刻,只有一個線程佔用CPU(單CPU)時間,但是無法知道在什麼時候,在什麼地方線程被打斷,這樣如何保證線程之間不破壞彼此的數據就顯得格外重要。同步問題是如此重要,也相當有趣,因而吸引了不少學者對他進行研究,由此產成了一系列經典的進程同步問題,其中較有代表性的是"生產者-消費者問題"、"讀者-寫者問題""哲學家進餐問題"等。在此,本文簡要討論了C++Builder平台下如何利用多線程編程技術實現"生產者-消費者"問題,幫助我們更好得理解同步概念及其實現方法。
生產者-消費者問題
生產者-消費者問題是一個著名的進程同步問題。它描述的是:有一群生產者進程在生產消息,並將此消息提供給消費者進程去消費。為使生產者進程和消費者進程能並發進行,在他們之間設置了一個具有N個緩沖區的緩沖池,生產者進程可以將它所生產的消息放入一個緩沖區中,消費者進程可以從一個緩沖區中取得一個消息消費。盡管所有的生產者進程和消費者進程都是以非同步方式進行的,但他們之間必須保持同步,即不允許消費者進程到一個空的緩沖區中去取消息,也不允許生產者進程向一個已裝滿消息且尚未被取走消息的緩沖區中投放消息。
C++Builder多線程應用程序編程基礎
1、使用C++Builder提供的TThread類
VCL類庫提供了用於線程編程的TThread類。在TThread類中封裝了Windows中關於線程機制的WindowsAPI。對於大多數的應用程序來說,可在應用程序中使用線程對象來表示執行線程。線程對象通過封裝使用線程所需的內容,簡化了多線程應用程序的編寫。注意,線程對象不允許控制線程堆棧的大小或其安全屬性。若需要控制這些,必須使用WindowsAPI的Create Thread()或Begin Thread()函數。
TThread類有以下一些屬性和方法:
1) 屬性:
·Priority:優先順序屬性。可以設置線程的優先順序。
·Return Value:返回值屬性。當線程介紹時返回給其他線程一個數值。
·Suspended:掛起屬性。可以判斷線程是否被掛起。
·Terminated:結束屬性。用來標志是否應該結束線程。
·ThreadID:標識號屬性。在整個系統中線程的標識號。使用Windows API函數時該屬性非常有用。
2) 方法:
·Do Terminate:產生一個On Terminate事件,但是不結束線程的執行。
·Resume:喚醒一個線程繼續執行。
·Suspend:掛起一個線程,要與Resume過程成對使用。
·Synchronize:由主VCL線程調用的一個同步過程。
·Terminate:將Terminate屬性設置為True,中止線程的執行。
·Wait For:等待線程的中止並返回Return Value屬性的數值。
2、協調線程
在編寫線程執行時運行的代碼時,必須考慮到可能同步執行的其他線程的行為。特別注意,避免兩個線程試圖同時使用相同的全局對象或變數。另外,一個線程中的代碼會依賴其他線程執行任務的結果。
1) 避免同時訪問
為避免在訪問全局對象或變數時與其他線程發生沖突,可能需要暫停其他線程的執行,直到該線程代碼完成操作。
(1)鎖定對象。一些對象內置了鎖定功能,以防止其他線程使用該對象的實例。例如,畫布對象(TCanvas及其派生類)有一種Lock()函數可以防止其他線程訪問畫布,直到調用Unlock()函數。顯然,這種方法只對部分類有效。
(2)使用重要區段。若對象沒有提供內置的鎖定功能,可使用重要區段。重要區段像門一樣,每次只允許一個線程進入,要使用重要區段,需創建TCriticalSection的全局實例。TCriticalSection有兩個函數:Acquire()(阻止其他線程執行該區域)及Release()(取消對其他線程的阻止)。
(3)使用多重讀、獨占寫的同步器。當使用重要區段來保護全局內存時,每次只有一個線程可以使用該內存。這種保護可能會超出了需要,特別是有一個經常讀但很少寫的對象或變數時更是如此。多個線程同時讀相同內存但沒有線程寫內存是沒有危險的。當有一些經常被讀,但是很少寫的全局變數時,可用對象保護它。這個對象和重要區段一樣,但它允許多個線程同時讀,只要沒有線程寫即可。每個需要讀內存的線程首先要調用Begin Read()函數(確保當前無其他線程寫內存),線程完成對保護內存讀操作後,要調用End Read()函數。任何線程需要防寫內存必須調用Begin Write()函數(確保當前無其他線程讀或寫內存),完成對保護內存寫操作後,調用End Write()函數。
(4)使用Synchronize函數:Void __fast call Synchronize (TThreadMethod &Method);
其中參數Method為一個不帶參數的過程名。在這個不帶參數的過程中是一些訪問VCL的代碼。我們可以在Execute過程中調用Synchronize過程來避免對VCL的並發訪問。程序運行期間的具體過程實際上是由Synchronize過程來通知主線程,然後主線程在適當的時機來執行Synchronize過程的參數列表中的那個不帶參數的過程。在多個線程的情況下,主線程將Synchronize過程發過來的通知放到消息隊列中,然後逐個地響應這些消息。通過這種機制Synchronize實現了線程之間地同步。
2) 等待其他線程
若線程必須等待另一線程完成某項任務,可讓線程臨時中斷執行。然後,要麼等待另一線程完全執行結束,要麼等待另一線程通知完成了該任務。
(1)等待線程執行結束
要等待另一線程執行結束,使用它地Wait For()函數。Wait For函數直到那個線程終止才返回,終止的方式要麼完成了其Execute()函數,要麼由於一個異常。
(2)等待任務完成。有時,只需要等待線程完成一些操作而不是等待線程執行結束。為此,可使用一個事件對象。事件對象(TEvent)應具有全局范圍以便他們能夠為所有線程可見。當一個線程完成一個被其他線程依賴的操作時,調用TEvent::Set Event()函數。Set Event發出一個信號,以便其他線程可以檢查並得知操作完成。要關掉信號,則使用Reset Event()函數。
例如,當必須等待若干線程完成其執行而不是單個線程時。因為不知道哪個線程最後完成,也就不能對某個線程使用Wait For()函數。此時,可通過調用Set Event以在線程結束時累加計數值並在最後一個線程結束時發出信號以指示所有線程結束。
多線程應用程序編程實例
下面是一個實現"生產者-消費者問題"的多線程應用實例。在此例中,我們按上面介紹的方法構造了兩個TThread的子類TProcerThread(生產者線程)和TCustomerThread(消費者線程),生產和消費的商品僅僅是一個整數。在協調生產和消費的過程中,重要區段(TCriticalSection)和事件(TEvent)得到了應用。生產者通過TEvent類的對象Begin Consume來通知消費者開始消費,而消費者通過TEent類的對象Begin Proce通知生產者開始生產。程序中共有兩個生產者,一個消費者。在兩個生產者之間,通過TCriticalSection類的對象同步。其運行界面如圖1所示。

圖1 程序運行效果

主要源程序如下所示:
生產者線程:
Void __fast call TProcerThread:: Execute ()
{
//---- Place thread code here ----
Int i = 0;
Int j;
while(i<100) //每個生產者線程生產100個商品
{
Sleep(1000);//延遲,為清楚得顯示執行效果
if(Form1->buffer_size > 0)//緩沖池不空,通知消費者消費
{
Form1->Begin Consumer->Set Event ();
}
Form1->Proce Guard->Acquire ();
i++;
StrResult = IntToStr (i);
J = Form1->buffer_size;
Form1->Proct [j] = i;
Form1->buffer_size++;
Synchron

轉載,僅供參考,祝你愉快,滿意請採納。

7. 關於C++多線程編程教學

在Windows NT和Windows 9x中,多線程的編程實現需要調用一系列的API函數,如CreateThread、ResumeThread等,比較麻煩而且容易出錯。我們使用Inprise公司的新一代RAD開發工具C++Builder,可以方便地實現多線程的編程。與老牌RAD工具Visual Basic和Delphi比,C++Builer不僅功能非常強大,而且它的編程語言是C++,對於系統開發語言是C的Windows系列操作系統,它具有其它編程語言無可比擬的優勢。利用C++Builder提供的TThread對象,多線程的編程變得非常簡便易用。那麼,如何實現呢?且待我慢慢道來,讓你體會一下多線程櫻配的強大功能。

1. 創建多線程程序:

首先,先介紹一下實現多線程的具體步驟。在C++Builder中雖然用Tthread對象說明了線程的概念,但是Tthread對象本身並不完整,需要在TThread下新建其子類,並重載Execute方法來使用線程對象。在C++Builder下可以很方便地實現這一點。

在C++Builder IDE環境下選擇菜單File|New,在肆李New欄中選中Thread Object,按OK,接下來彈出輸入框,輸入TThread對象子類的名字MyThread,這樣C++Builder自動為你創建了一個名為TMyThread的TThread子類。同時編輯器中多了一個名為Unit2.cpp的單元,這就是我們創建的TMyThread子類脊雹指的原碼,如下:

#include
#pragma hdrstop

#include 「Unit2.h」
#pragma package(smart_init)
//---------------------
// Important: Methods and properties of objects in VCL can only be
// used in a method called using Synchronize, for example:
//
// Synchronize(UpdateCaption);
//
// where UpdateCaption could look like:
//
// void __fastcall MyThread::UpdateCaption()
// {
// Form1->Caption = 「Updated in a thread」;
// }
//--------------------
__fastcall MyThread::MyThread(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
//--------------------
void __fastcall MyThread::Execute()
{
//---- Place thread code here ----
}
//---------------------

其中的Execute()函數就是我們要在線程中實現的任務的代碼所在處。在原代碼中包含Unit2.cpp,這個由我們創建的TMyThread對象就可以使用了。使用時,動態創建一個TMyThread 對象,在構造函數中使用Resume()方法,那麼程序中就增加了一個新的我們自己定義的線程TMyThread,具體執行的代碼就是Execute()方法重載的代碼。要載入更多的線程,沒關系,只要繼續創建需要數量的TMyThread 對象就成。

8. 多線程的java 程序如何編寫

Java 給多線程編程提供了內置的支持。 一條線程指的是進程中一個單一順序的控制流,一個進程中可以並發多個線程,每條線程並行執行不同的任務。

9. Java多線程程序設計初步入門

在Java語言產生前 傳統的程序設計語言的程序同一時刻只能單任務操作 效率非常低 例如程序往往在接收數據輸入時發生阻塞 只有等到程序獲得數據後才能繼續運行 隨著Internet的迅猛發展 這種狀況越來越不能讓人們忍受 如果網路接收數據阻塞 後台程序就處於等待狀態而不繼續任何操作 而這種阻塞是經常會碰到的 此時CPU資源被白白的閑置起來 如果在後台程序中能夠同時處理多個任務 該多好啊!應Internet技術而生的Java語言解決了這個問題 多線程程序是Java語言的一個很重要的特點 在一個Java程序中 我們可以同時並行運行多個相對獨立的線程 例如 我們如果創建一個線程來進行數據輸入輸出 而創建另一個線程在後台進行其它的數據處理 如果輸入輸出線程在接收數據時阻塞 而處理數據的線程仍然在運行 多線程程序設計大大提高了程序執行效率和處理能力

線程的創建

我們知道Java是面向對象的程序語言 用Java進行程序設計就是設計和使用類 Java為我們提供了線程類Thread來創建線程 創建線程與創建普通鬧梁的類的對象的操作是一樣的 而線程就是Thread類或其子類的實例對象 下面是一個創建啟動一個線程的語句

Thread thread =new Thread(); file://聲明困彎神一個對象實例 即創建一個線程

Thread run(); file://用Thread類中的run()方法啟動線程

從這個例子 我們可以通過Thread()構造方法創建一個線程 並啟動該線程 事實上 啟動線程 也就是啟動線程的run()方法 而Thread類中的run()方法沒有任何操作語句 所以這個線程沒有任何操作 要使線程實現預定功能 必須定義自己的run()方法 Java中通常有兩種方式定義run()方法

通過定義一個Thread類的子類 在該子類中重寫run()方法 Thread子類的實例對象就是一個線程 顯然 該線程汪虧有我們自己設計的線程體run()方法 啟動線程就啟動了子類中重寫的run()方法

通過Runnable介面 在該介面中定義run()方法的介面 所謂介面跟類非常類似 主要用來實現特殊功能 如復雜關系的多重繼承功能 在此 我們定義一個實現Runnable() 介面的類 在該類中定義自己的run()方法 然後以該類的實例對象為參數調用Thread類的構造方法來創建一個線程

線程被實際創建後處於待命狀態 激活(啟動)線程就是啟動線程的run()方法 這是通過調用線程的start()方法來實現的

下面一個例子實踐了如何通過上述兩種方法創建線程並啟動它們

// 通過Thread類的子類創建的線程 class thread extends Thread { file://自定義線程的run()方法 public void run() { System out println( Thread is running… ); } } file://通過Runnable介面創建的另外一個線程 class thread implements Runnable { file://自定義線程的run()方法 public void run() { System out println( Thread is running… ); } } file://程序的主類 class Multi_Thread file://聲明主類 { plubic static void mail(String args[]) file://聲明主方法 { thread threadone=new thread (); file://用Thread類的子類創建線程 Thread threado=new Thread(new thread ()); file://用Runnable介面類的對象創建線程 threadone start(); threado start(); file://strat()方法啟動線程 } }

運行該程序就可以看出 線程threadone和threado交替佔用CPU 處於並行運行狀態 可以看出 啟動線程的run()方法是通過調用線程的start()方法來實現的(見上例中主類) 調用start()方法啟動線程的run()方法不同於一般的調用方法 調用一般方法時 必須等到一般方法執行完畢才能夠返回start()方法 而啟動線程的run()方法後 start()告訴系統該線程准備就緒可以啟動run()方法後 就返回start()方法執行調用start()方法語句下面的語句 這時run()方法可能還在運行 這樣 線程的啟動和運行並行進行 實現了多任務操作

線程的優先順序

對於多線程程序 每個線程的重要程度是不盡相同 如多個線程在等待獲得CPU時間時 往往我們需要優先順序高的線程優先搶佔到CPU時間得以執行 又如多個線程交替執行時 優先順序決定了級別高的線程得到CPU的次數多一些且時間多長一些 這樣 高優先順序的線程處理的任務效率就高一些

Java中線程的優先順序從低到高以整數 ~ 表示 共分為 級 設置優先順序是通過調用線程對象的setPriority()方法 如上例中 設置優先順序的語句為

thread threadone=new thread (); file://用Thread類的子類創建線程

Thread threado=new Thread(new thread ()); file://用Runnable介面類的對象創建線程

threadone setPriority( ); file://設置threadone的優先順序

threado setPriority( ); file://設置threado的優先順序

threadone start(); threado start(); file://strat()方法啟動線程

這樣 線程threadone將會優先於線程threado執行 並將佔有更多的CPU時間 該例中 優先順序設置放在線程啟動前 也可以在啟動後進行設置 以滿足不同的優先順序需求

線程的(同步)控制

一個Java程序的多線程之間可以共享數據 當線程以非同步方式訪問共享數據時 有時候是不安全的或者不和邏輯的 比如 同一時刻一個線程在讀取數據 另外一個線程在處理數據 當處理數據的線程沒有等到讀取數據的線程讀取完畢就去處理數據 必然得到錯誤的處理結果 這和我們前面提到的讀取數據和處理數據並行多任務並不矛盾 這兒指的是處理數據的線程不能處理當前還沒有讀取結束的數據 但是可以處理其它的數據

如果我們採用多線程同步控制機制 等到第一個線程讀取完數據 第二個線程才能處理該數據 就會避免錯誤 可見 線程同步是多線程編程的一個相當重要的技術

在講線程的同步控制前我們需要交代如下概念

用Java關鍵字synchonized同步對共享數據操作的方法

在一個對象中 用synchonized聲明的方法為同步方法 Java中有一個同步模型 監視器 負責管理線程對對象中的同步方法的訪問 它的原理是 賦予該對象唯一一把 鑰匙 當多個線程進入對象 只有取得該對象鑰匙的線程才可以訪問同步方法 其它線程在該對象中等待 直到該線程用wait()方法放棄這把鑰匙 其它等待的線程搶占該鑰匙 搶佔到鑰匙的線程後才可得以執行 而沒有取得鑰匙的線程仍被阻塞在該對象中等待

file://聲明同步的一種方式 將方法聲明同步

class store {public synchonized void store_in(){… }public synchonized void store_out(){ … }}

利用wait() notify()及notifyAll()方法發送消息實現線程間的相互聯系

Java程序中多個線程通過消息來實現互動聯系的 這幾種方法實現了線程間的消息發送 例如定義一個對象的synchonized 方法 同一時刻只能夠有一個線程訪問該對象中的同步方法 其它線程被阻塞 通常可以用notify()或notifyAll()方法喚醒其它一個或所有線程 而使用wait()方法來使該線程處於阻塞狀態 等待其它的線程用notify()喚醒

一個實際的例子就是生產和銷售 生產單元將產品生產出來放在倉庫中 銷售單元則從倉庫中提走產品 在這個過程中 銷售單元必須在倉庫中有產品時才能提貨 如果倉庫中沒有產品 則銷售單元必須等待

程序中 假如我們定義一個倉庫類store 該類的實例對象就相當於倉庫 在store類中定義兩個成員方法 store_in() 用來模擬產品製造者往倉庫中添加產品 strore_out()方法則用來模擬銷售者從倉庫中取走產品 然後定義兩個線程類 customer類 其中的run()方法通過調用倉庫類中的store_out()從倉庫中取走產品 模擬銷售者 另外一個線程類procer中的run()方法通過調用倉庫類中的store_in()方法向倉庫添加產品 模擬產品製造者 在主類中創建並啟動線程 實現向倉庫中添加產品或取走產品

如果倉庫類中的store_in() 和store_out()方法不聲明同步 這就是個一般的多線程 我們知道 一個程序中的多線程是交替執行的 運行也是無序的 這樣 就可能存在這樣的問題

倉庫中沒有產品了 銷售者還在不斷光顧 而且還不停的在 取 產品 這在現實中是不可思義的 在程序中就表現為負值 如果將倉庫類中的stroe_in()和store_out()方法聲明同步 如上例所示 就控制了同一時刻只能有一個線程訪問倉庫對象中的同步方法 即一個生產類線程訪問被聲明為同步的store_in()方法時 其它線程將不能夠訪問對象中的store_out()同步方法 當然也不能訪問store_in()方法 必須等到該線程調用wait()方法放棄鑰匙 其它線程才有機會訪問同步方法

lishixin/Article/program/Java/gj/201311/27301

10. 關於Java多線程的(高手請幫忙)

package First;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;

import com.sun.media.sound.Toolkit;

public class test {
static int num = 0;
public static void main(String[] args) {
System.out.println("now:" + num );
new test().start();
}

class Thd implements Runnable{//創建線程

public void run() {
num ++;
System.out.println( num + "\n");
}
}

class Thd1 implements Runnable{//創建線程
public void run() {
num --;
System.out.println( num + "\n");
}
}

public void start() {
for ( int i = 0;i < 2; i ++){
Thd th1 = new Thd();
new Thread(th1).start();//線程啟動
}
for ( int i = 0;i < 2; i ++){
Thd1 th = new Thd1();
new Thread(th).start();//線程啟動
}
}
}

閱讀全文

與編程多線程序怎麼使用相關的資料

熱點內容
微信支付獲取code 瀏覽:28
微信手機傳文件給好友 瀏覽:605
初學編程有什麼好處 瀏覽:774
word2007拼寫檢查 瀏覽:454
魔獸世界41升級補丁 瀏覽:209
51單片機熱敏電阻測溫程序 瀏覽:913
專賣機油是哪個app 瀏覽:574
表格有密碼怎麼辦 瀏覽:376
立項文件費用多少 瀏覽:408
怎樣刪除電腦桌面的壓縮文件 瀏覽:139
b超單子哪個數據能看出來 瀏覽:75
vscodejs方法跳轉 瀏覽:609
java編程語言及版本號 瀏覽:219
兩條數據線多少錢 瀏覽:978
阿里雲盤一次可以保存多少個文件 瀏覽:179
揚州防控15號文件內容 瀏覽:424
nuke視頻教程網盤 瀏覽:714
朋友微信發給我的壓縮文件錯誤 瀏覽:334
銀飾拍攝教程 瀏覽:528
鄰居找不到無線網路連接怎麼辦 瀏覽:58

友情鏈接