欧美色欧美亚洲高清在线观看,国产特黄特色a级在线视频,国产一区视频一区欧美,亚洲成a 人在线观看中文

  1. <ul id="fwlom"></ul>

    <object id="fwlom"></object>

    <span id="fwlom"></span><dfn id="fwlom"></dfn>

      <object id="fwlom"></object>

      多線程編程知識總結(jié)

      時間:2019-05-12 03:57:17下載本文作者:會員上傳
      簡介:寫寫幫文庫小編為你整理了多篇相關(guān)的《多線程編程知識總結(jié)》,但愿對你工作學(xué)習(xí)有幫助,當(dāng)然你在寫寫幫文庫還可以找到更多《多線程編程知識總結(jié)》。

      第一篇:多線程編程知識總結(jié)

      多線程編程

      一、問題的提出

      1.1問題的引出

      編寫一個耗時的單線程程序:

      新建一個基于對話框的應(yīng)用程序SingleThread,在主對話框IDD_SINGLETHREAD_DIALOG添加一個按鈕,ID為IDC_SLEEP_SIX_SECOND,標(biāo)題為“延時6秒”,添加按鈕的響應(yīng)函數(shù),代碼如下:

      void CSingleThreadDlg::OnSleepSixSecond(){ Sleep(6000);//延時6秒 } 編譯并運行應(yīng)用程序,單擊“延時6秒”按鈕,你就會發(fā)現(xiàn)在這6秒期間程序就象“死機”一樣,不在響應(yīng)其它消息。為了更好地處理這種耗時的操作,我們有必要學(xué)習(xí)——多線程編程。

      1.2多線程概述

      進程和線程都是操作系統(tǒng)的概念。進程是應(yīng)用程序的執(zhí)行實例,每個進程是由私有的虛擬地址空間、代碼、數(shù)據(jù)和其它各種系統(tǒng)資源組成,進程在運行過程中創(chuàng)建的資源隨著進程的終止而被銷毀,所使用的系統(tǒng)資源在進程終止時被釋放或關(guān)閉。

      線程是進程內(nèi)部的一個執(zhí)行單元。系統(tǒng)創(chuàng)建好進程后,實際上就啟動執(zhí)行了該進程的主執(zhí)行線程,主執(zhí)行線程以函數(shù)地址形式,比如說main或WinMain函數(shù),將程序的啟動點提供給Windows系統(tǒng)。主執(zhí)行線程終止了,進程也就隨之終止。

      每一個進程至少有一個主執(zhí)行線程,它無需由用戶去主動創(chuàng)建,是由系統(tǒng)自動創(chuàng)建的。用戶根據(jù)需要在應(yīng)用程序中創(chuàng)建其它線程,多個線程并發(fā)地運行于同一個進程中。一個進程中的所有線程都在該進程的虛擬地址空間中,共同使用這些虛擬地址空間、全局變量和系統(tǒng)資源,所以線程間的通訊非常方便,多線程技術(shù)的應(yīng)用也較為廣泛。

      多線程可以實現(xiàn)并行處理,避免了某項任務(wù)長時間占用CPU時間。要說明的一點是,對于單處理器(CPU)的,為了運行所有這些線程,操作系統(tǒng)為每個獨立線程安排一些CPU時間,操作系統(tǒng)以輪換方式向線程提供時間片,這就給人一種假象,好象這些線程都在同時運行。由此可見,如果兩個非?;钴S的線程為了搶奪對CPU的控制權(quán),在線程切換時會消耗很多的CPU資源,反而會降低系統(tǒng)的性能。這一點在多線程編程時應(yīng)該注意。

      Win32 SDK函數(shù)支持進行多線程的程序設(shè)計,并提供了操作系統(tǒng)原理中的各種同步、互斥和臨界區(qū)等操作。Visual C++中,使用MFC類庫也實現(xiàn)了多線程的程序設(shè)計,使得多線程編程更加方便。1.3 Win32 API對多線程編程的支持

      Win32 提供了一系列的API函數(shù)來完成線程的創(chuàng)建、掛起、恢復(fù)、終結(jié)以及通信等工作。下面將選取其中的一些重要函數(shù)進行說明。

      1、HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);該函數(shù)在其調(diào)用進程的進程空間里創(chuàng)建一個新的線程,并返回已建線程的句柄,其中各參數(shù)說明如下:

      lpThreadAttributes:指向一個 SECURITY_ATTRIBUTES 結(jié)構(gòu)的指針,該結(jié)構(gòu)決定了線程的安全屬性,一般置為 NULL;

      dwStackSize:指定了線程的堆棧深度,一般都設(shè)置為0;

      lpStartAddress:表示新線程開始執(zhí)行時代碼所在函數(shù)的地址,即線程的起始地址。一般情況為(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc 是線程函數(shù)名;

      lpParameter:指定了線程執(zhí)行時傳送給線程的32位參數(shù),即線程函數(shù)的參數(shù);

      dwCreationFlags:控制線程創(chuàng)建的附加標(biāo)志,可以取兩種值。如果該參數(shù)為0,線程在被創(chuàng)建后就會立即開始執(zhí)行;如果該參數(shù)為CREATE_SUSPENDED,則系統(tǒng)產(chǎn)生線程后,該線程處于掛起狀態(tài),并不馬上執(zhí)行,直至函數(shù)ResumeThread被調(diào)用;

      lpThreadId:該參數(shù)返回所創(chuàng)建線程的ID;

      如果創(chuàng)建成功則返回線程的句柄,否則返回NULL。

      2、DWORD SuspendThread(HANDLE hThread);該函數(shù)用于掛起指定的線程,如果函數(shù)執(zhí)行成功,則線程的執(zhí)行被終止。

      3、DWORD ResumeThread(HANDLE hThread);該函數(shù)用于結(jié)束線程的掛起狀態(tài),執(zhí)行線程。

      4、VOID ExitThread(DWORD dwExitCode);該函數(shù)用于線程終結(jié)自身的執(zhí)行,主要在線程的執(zhí)行函數(shù)中被調(diào)用。其中參數(shù)dwExitCode用來設(shè)置線程的退出碼。

      5、BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);

      一般情況下,線程運行結(jié)束之后,線程函數(shù)正常返回,但是應(yīng)用程序可以調(diào)用TerminateThread強行終止某一線程的執(zhí)行。各參數(shù)含義如下: hThread:將被終結(jié)的線程的句柄;

      dwExitCode:用于指定線程的退出碼。

      使用TerminateThread()終止某個線程的執(zhí)行是不安全的,可能會引起系統(tǒng)不穩(wěn)定;雖然該函數(shù)立即終止線程的執(zhí)行,但并不釋放線程所占用的資源。因此,一般不建議使用該函數(shù)。

      6、BOOL PostThreadMessage(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam);該函數(shù)將一條消息放入到指定線程的消息隊列中,并且不等到消息被該線程處理時便返回。idThread:將接收消息的線程的ID;

      Msg:指定用來發(fā)送的消息;

      wParam:同消息有關(guān)的字參數(shù);

      lParam:同消息有關(guān)的長參數(shù);

      調(diào)用該函數(shù)時,如果即將接收消息的線程沒有創(chuàng)建消息循環(huán),則該函數(shù)執(zhí)行失敗。

      1.4.Win32 API多線程編程例程

      例程1 [MultiThread1] 一個簡單的線程。注意事項:

      ? Volatile:關(guān)鍵字:

      volatile是要求C++編譯器不要自作聰明的把變量緩沖在寄存器里.因為該變量可能會被意外的修改。(多個線程或其他原因)

      如從串口讀數(shù)據(jù)的場合,把變量緩沖在寄存器里,下次去讀寄存器就沒有意義了.因為串口的數(shù)據(jù)可能隨時會改變的.加鎖訪問用于多個線程的場合.在進入臨界區(qū)時是肯定要加鎖的.volatile也加上,以保證從內(nèi)存中讀取變量的值.? 終止線程:

      Windows終止線程運行的四種方法 終止線程運行

      若要終止線程的運行,可以使用下面的方法:

      ? 線程函數(shù)返回(最好使用這種方法)。

      ? 通過調(diào)用 ExitThread 函數(shù),線程將自行撤消(最好不要使用這種方法)。

      ? 同一個進程或另一個進程中的線程調(diào)用 TerminateThread 函數(shù)(應(yīng)該避免使用這種方法)。

      ? 包含線程的進程終止運行(應(yīng)該避免使用這種方法)。

      下面將介紹終止線程運行的方法,并且說明線程終止運行時會出現(xiàn)什么情況。

      ? 線程函數(shù)返回

      始終都應(yīng)該將線程設(shè)計成這樣的形式,即當(dāng)想要線程終止運行時,它們就能夠返回。這是確保所有線程資源被正確地清除的唯一辦法。

      如果線程能夠返回,就可以確保下列事項的實現(xiàn):

      ? 在線程函數(shù)中創(chuàng)建的所有 C++ 對象均將通過它們的撤消函數(shù)正確地撤消。

      ? 操作系統(tǒng)將正確地釋放線程堆棧使用的內(nèi)存。

      ? 系統(tǒng)將線程的退出代碼(在線程的內(nèi)核對象中維護)設(shè)置為線程函數(shù)的返回值。

      ? 系統(tǒng)將遞減線程內(nèi)核對象的使用計數(shù)。? 使用 ExitThread 函數(shù)

      可以讓線程調(diào)用 ExitThread 函數(shù),以便強制線程終止運行:

      VOID ExitThread(DWORD dwExitCode);

      該函數(shù)將終止線程的運行,并導(dǎo)致操作系統(tǒng)清除該線程使用的所有操作系統(tǒng)資源。但是,C++ 資源(如 C++ 類對象)將不被撤消。由于這個原因,最好從線程函數(shù)返回,而不是通過調(diào)用 ExitThread 來返回。

      當(dāng)然,可以使用 ExitThread 的 dwExitThread 參數(shù)告訴系統(tǒng)將線程的退出代碼設(shè)置為什么。ExitThread 函數(shù)并不返回任何值,因為線程已經(jīng)終止運行,不能執(zhí)行更多的代碼。? 使用 TerminateThread 函數(shù)

      調(diào)用 TerminateThread 函數(shù)也能夠終止線程的運行:

      BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode);

      與 ExitThread 不同,ExitThread 總是撤消調(diào)用的線程,而 TerminateThread 能夠撤消任何線程。hThread 參數(shù)用于標(biāo)識被終止運行的線程的句柄。當(dāng)線程終止運行時,它的退出代碼成為你作為 dwExitCode 參數(shù)傳遞的值。同時,線程的內(nèi)核對象的使用計數(shù)也被遞減。

      注意 TerminateThread 函數(shù)是異步運行的函數(shù),也就是說,它告訴系統(tǒng)你想要線程終止運行,但是,當(dāng)函數(shù)返回時,不能保證線程被撤消。如果需要確切地知道該線程已經(jīng)終止運行,必須調(diào)用 WaitForSingleObject 或者類似的函數(shù),傳遞線程的句柄。

      設(shè)計良好的應(yīng)用程序從來不使用這個函數(shù),因為被終止運行的線程收不到它被撤消的通知。線程不能正確地清除,并且不能防止自己被撤消。

      注意 當(dāng)使用返回或調(diào)用 ExitThread 的方法撤消線程時,該線程的內(nèi)存堆棧也被撤消。但是,如果使用 TerminateThread,那么在擁有線程的進程終止運行之前,系統(tǒng)不撤消該線程的堆棧。Microsoft故意用這種方法來實現(xiàn) TerminateThread。如果其他仍然正在執(zhí)行的線程要引用強制撤消的線程堆棧上的值,那么其他的線程就會出現(xiàn)訪問違規(guī)的問題。如果將已經(jīng)撤消的線程的堆棧留在內(nèi)存中,那么其他線程就可以繼續(xù)很好地運行。

      此外,當(dāng)線程終止運行時,DLL 通常接收通知。如果使用 TerminateThread 強迫線程終止,DLL 就不接收通知,這能阻止適當(dāng)?shù)那宄谶M程終止運行時撤消線程。當(dāng)線程終止運行時,會發(fā)生下列操作:

      ? 線程擁有的所有用戶對象均被釋放。在 Windows 中,大多數(shù)對象是由包含創(chuàng)建這些對象的線程的進程擁有的。但是一個線程擁有兩個用戶對象,即窗口和掛鉤。當(dāng)線程終止運行時,系統(tǒng)會自動撤消任何窗口,并且卸載線程創(chuàng)建的或安裝的任何掛鉤。其他對象只有在擁有線程的進程終止運行時才被撤消。

      ? 線程的退出代碼從 STILL_ACTIVE 改為傳遞給 ExitThread 或 TerminateThread 的代碼。

      ? 線程內(nèi)核對象的狀態(tài)變?yōu)橐淹ㄖ?/p>

      ? 如果線程是進程中最后一個活動線程,系統(tǒng)也將進程視為已經(jīng)終止運行。

      ? 線程內(nèi)核對象的使用計數(shù)遞減 1。

      當(dāng)一個線程終止運行時,在與它相關(guān)聯(lián)的線程內(nèi)核對象的所有未結(jié)束的引用關(guān)閉之前,該內(nèi)核對象不會自動被釋放。

      一旦線程不再運行,系統(tǒng)中就沒有別的線程能夠處理該線程的句柄。然而別的線程可以調(diào)用 GetExitcodeThread 來檢查由 hThread 標(biāo)識的線程是否已經(jīng)終止運行。如果它已經(jīng)終止運行,則確定它的退出代碼:

      BOOL GetExitCodeThread(HANDLE hThread, PDOWRD pdwExitCode);退出代碼的值在 pdwExitCode 指向的 DWORD 中返回。如果調(diào)用 GetExitCodeThread 時線程尚未終止運行,該函數(shù)就用 STILL_ACTIVE 標(biāo)識符(定義為 0x103)填入 DWORD。如果該函數(shù)運行成功,便返回 TRUE。

      ? 線程的定義:

      例程2[MultiThread2] 傳送一個一個整型的參數(shù)到一個線程中,以及如何等待一個線程完成處理。

      DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);

      hHandle:為要監(jiān)視的對象(一般為同步對象,也可以是線程)的句柄;

      dwMilliseconds:為hHandle對象所設(shè)置的超時值,單位為毫秒;

      當(dāng)在某一線程中調(diào)用該函數(shù)時,線程暫時掛起,系統(tǒng)監(jiān)視hHandle所指向的對象的狀態(tài)。如果在掛起的dwMilliseconds毫秒內(nèi),線程所等待的對象變?yōu)橛行盘枲顟B(tài),則該函數(shù)立即返回;如果超時時間已經(jīng)到達dwMilliseconds毫秒,但hHandle所指向的對象還沒有變成有信號狀態(tài),函數(shù)照樣返回。參數(shù)dwMilliseconds有兩個具有特殊意義的值:0和INFINITE。若為0,則該函數(shù)立即返回;若為INFINITE,則線程一直被掛起,直到hHandle所指向的對象變?yōu)橛行盘枲顟B(tài)時為止。

      例程3[MultiThread3] 傳送一個結(jié)構(gòu)體給一個線程函數(shù),可以通過傳送一個指向結(jié)構(gòu)體的指針參數(shù)來完成。補充一點:如果你在void CMultiThread3Dlg::OnStart()函數(shù)中添加/* */語句,編譯運行你就會發(fā)現(xiàn)進度條不進行刷新,主線程也停止了反應(yīng)。什么原因呢?這是因為WaitForSingleObject函數(shù)等待子線程(ThreadFunc)結(jié)束時,導(dǎo)致了線程死鎖。因為WaitForSingleObject函數(shù)會將主線程掛起(任何消息都得不到處理),而子線程ThreadFunc正在設(shè)置進度條,一直在等待主線程將刷新消息處理完畢返回才會檢測通知事件。這樣兩個線程都在互相等待,死鎖發(fā)生了,編程時應(yīng)注意避免。

      例程4[MultiThread4] 測試在Windows下最多可創(chuàng)建線程的數(shù)目。

      二、MFC中的多線程開發(fā)

      2.1 MFC對多線程編程的支持

      MFC中有兩類線程,分別稱之為工作者線程和用戶界面線程。二者的主要區(qū)別在于工作者線程沒有消息循環(huán),而用戶界面線程有自己的消息隊列和消息循環(huán)。

      工作者線程沒有消息機制,通常用來執(zhí)行后臺計算和維護任務(wù),如冗長的計算過程,打印機的后臺打印等。用戶界面線程一般用于處理獨立于其他線程執(zhí)行之外的用戶輸入,響應(yīng)用戶及系統(tǒng)所產(chǎn)生的事件和消息等。但對于Win32的API編程而言,這兩種線程是沒有區(qū)別的,它們都只需線程的啟動地址即可啟動線程來執(zhí)行任務(wù)。

      在MFC中,一般用全局函數(shù)AfxBeginThread()來創(chuàng)建并初始化一個線程的運行,該函數(shù)有兩種重載形式,分別用于創(chuàng)建工作者線程和用戶界面線程。兩種重載函數(shù)原型和參數(shù)分別說明如下:

      (1)CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,LPVOID pParam,nPriority=THREAD_PRIORITY_NORMAL,UINT nStackSize=0,DWORD dwCreateFlags=0,LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);

      PfnThreadProc:指向工作者線程的執(zhí)行函數(shù)的指針,線程函數(shù)原型必須聲明如下: UINT ExecutingFunction(LPVOID pParam);請注意,ExecutingFunction()應(yīng)返回一個UINT類型的值,用以指明該函數(shù)結(jié)束的原因。一般情況下,返回0表明執(zhí)行成功。

      pParam:傳遞給線程函數(shù)的一個32位參數(shù),執(zhí)行函數(shù)將用某種方式解釋該值。它可以是數(shù)值,或是指向一個結(jié)構(gòu)的指針,甚至可以被忽略;

      nPriority:線程的優(yōu)先級。如果為0,則線程與其父線程具有相同的優(yōu)先級;

      nStackSize:線程為自己分配堆棧的大小,其單位為字節(jié)。如果nStackSize被設(shè)為0,則線程的堆棧被設(shè)置成與父線程堆棧相同大小; dwCreateFlags:如果為0,則線程在創(chuàng)建后立刻開始執(zhí)行。如果為CREATE_SUSPEND,則線程在創(chuàng)建后立刻被掛起;

      lpSecurityAttrs:線程的安全屬性指針,一般為NULL;

      (2)CWinThread* AfxBeginThread(CRuntimeClass* pThreadClass,int nPriority=THREAD_PRIORITY_NORMAL,UINT nStackSize=0,DWORD dwCreateFlags=0,LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);

      pThreadClass 是指向 CWinThread 的一個導(dǎo)出類的運行時類對象的指針,該導(dǎo)出類定義了被創(chuàng)建的用戶界面線程的啟動、退出等;其它參數(shù)的意義同形式1。使用函數(shù)的這個原型生成的線程也有消息機制,在以后的例子中我們將發(fā)現(xiàn)同主線程的機制幾乎一樣。下面對CWinThread類的數(shù)據(jù)成員及常用函數(shù)進行簡要說明。

      ? ? ? m_hThread:當(dāng)前線程的句柄;

      m_nThreadID:當(dāng)前線程的ID;

      m_pMainWnd:指向應(yīng)用程序主窗口的指針

      virtual BOOL CWinThread::InitInstance();重載該函數(shù)以控制用戶界面線程實例的初始化。初始化成功則返回非0值,否則返回0。用戶界面線程經(jīng)常重載該函數(shù),工作者線程一般不使用InitInstance()。

      virtual int CWinThread::ExitInstance();在線程終結(jié)前重載該函數(shù)進行一些必要的清理工作。該函數(shù)返回線程的退出碼,0表示執(zhí)行成功,非0值用來標(biāo)識各種錯誤。同InitInstance()成員函數(shù)一樣,該函數(shù)也只適用于用戶界面線程。

      2.2 MFC多線程編程實例

      例程5 MultiThread5 為了與Win32 API對照,使用MFC 類庫編程實現(xiàn)例程3 MultiThread3。

      例程6 MultiThread6[用戶界面線程] ? 創(chuàng)建用戶界面線程的步驟:

      1.使用ClassWizard創(chuàng)建類CWinThread的派生類(以CUIThread類為例)class CUIThread : public CWinThread { DECLARE_DYNCREATE(CUIThread)protected: CUIThread();// protected constructor used by dynamic creation

      // Attributes public: // Operations public:

      // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CUIThread)public: virtual BOOL InitInstance();virtual int ExitInstance();//}}AFX_VIRTUAL // Implementation protected: virtual ~CUIThread();// Generated message map functions //{{AFX_MSG(CUIThread)

      // NOTE-the ClassWizard will add and remove member functions here.//}}AFX_MSG

      DECLARE_MESSAGE_MAP()};

      2.重載函數(shù)InitInstance()和ExitInstance()。BOOL CUIThread::InitInstance(){ CFrameWnd* wnd=new CFrameWnd;wnd->Create(NULL,“UI Thread Window”);wnd->ShowWindow(SW_SHOW);wnd->UpdateWindow();m_pMainWnd=wnd;return TRUE;}

      3.創(chuàng)建新的用戶界面線程 void CUIThreadDlg::OnButton1(){

      }

      請注意以下兩點:

      A、在UIThreadDlg.cpp的開頭加入語句: #include “UIThread.h” B、把UIThread.h中類CUIThread()的構(gòu)造函數(shù)的特性由 protected 改為 public。CUIThread* pThread=new CUIThread();pThread->CreateThread();

      用戶界面線程的執(zhí)行次序與應(yīng)用程序主線程相同,首先調(diào)用用戶界面線程類的InitInstance()函數(shù),如果返回TRUE,繼續(xù)調(diào)用線程的Run()函數(shù),該函數(shù)的作用是運行一個標(biāo)準(zhǔn)的消息循環(huán),并且當(dāng)收到WM_QUIT消息后中斷,在消息循環(huán)過程中,Run()函數(shù)檢測到線程空閑時(沒有消息),也將調(diào)用OnIdle()函數(shù),最后Run()函數(shù)返回,MFC調(diào)用ExitInstance()函數(shù)清理資源。

      你可以創(chuàng)建一個沒有界面而有消息循環(huán)的線程,例如:你可以從CWinThread派生一個新類,在InitInstance函數(shù)中完成某項任務(wù)并返回FALSE,這表示僅執(zhí)行InitInstance函數(shù)中的任務(wù)而不執(zhí)行消息循環(huán),你可以通過這種方法,完成一個工作者線程的功能。

      三、線程間通訊

      3.1通訊方式

      一般而言,應(yīng)用程序中的一個次要線程總是為主線程執(zhí)行特定的任務(wù),這樣,主線程和次要線程間必定有一個信息傳遞的渠道,也就是主線程和次要線程間要進行通信。這種線程間的通信不但是難以避免的,而且在多線程編程中也是復(fù)雜和頻繁的,下面將進行說明。

      3.1.1使用全局變量進行通信

      由于屬于同一個進程的各個線程共享操作系統(tǒng)分配該進程的資源,故解決線程間通信最簡單的一種方法是使用全局變量。對于標(biāo)準(zhǔn)類型的全局變量,建議使用volatile 修飾符,它告訴編譯器無需對該變量作任何的優(yōu)化,即無需將它放到一個寄存器中,并且該值可被外部改變。如果線程間所需傳遞的信息較復(fù)雜,可以定義一個結(jié)構(gòu),通過傳遞指向該結(jié)構(gòu)的指針進行傳遞信息。

      3.1.2使用自定義消息

      可以在一個線程的執(zhí)行函數(shù)中向另一個線程發(fā)送自定義的消息來達到通信的目的。一個線程向另外一個線程發(fā)送消息是通過操作系統(tǒng)實現(xiàn)的。利用Windows操作系統(tǒng)的消息驅(qū)動機制,當(dāng)一個線程發(fā)出一條消息時,操作系統(tǒng)首先接收到該消息,然后把該消息轉(zhuǎn)發(fā)給目標(biāo)線程,接收消息的線程必須已經(jīng)建立了消息循環(huán)。

      3.2例程

      例程GlobalObjectTest 該例程演示了如何利用全局變量進行通信

      例程7[MultiThread7] 該例程演示了如何使用自定義消息進行線程間通信。首先,主線程向CCalculateThread線程發(fā)送消息WM_CALCULATE,CCalculateThread線程收到消息后進行計算,再向主線程發(fā)送WM_DISPLAY消息,主線程收到該消息后顯示計算結(jié)果。步驟:

      四、線程的同步

      4.1基本概念

      雖然多線程能給我們帶來好處,但是也有不少問題需要解決。例如,對于像磁盤驅(qū)動器這樣獨占性系統(tǒng)資源,由于線程可以執(zhí)行進程的任何代碼段,且線程的運行是由系統(tǒng)調(diào)度自動完成的,具有一定的不確定性,因此就有可能出現(xiàn)兩個線程同時對磁盤驅(qū)動器進行操作,從而出現(xiàn)操作錯誤;又例如,對于銀行系統(tǒng)的計算機來說,可能使用一個線程來更新其用戶數(shù)據(jù)庫,而用另外一個線程來讀取數(shù)據(jù)庫以響應(yīng)儲戶的需要,極有可能讀數(shù)據(jù)庫的線程讀取的是未完全更新的數(shù)據(jù)庫,因為可能在讀的時候只有一部分?jǐn)?shù)據(jù)被更新過。

      使隸屬于同一進程的各線程協(xié)調(diào)一致地工作稱為線程的同步。MFC提供了多種同步對象,下面只介紹最常用的四種:

      臨界區(qū)(CCriticalSection)

      事件(CEvent)

      互斥量(CMutex)

      信號量(CSemaphore)

      通過這些類,可以比較容易地做到線程同步。

      4.2使用 CCriticalSection 類

      當(dāng)多個線程訪問一個獨占性共享資源時,可以使用“臨界區(qū)”對象。任一時刻只有一個線程可以擁有臨界區(qū)對象,擁有臨界區(qū)的線程可以訪問被保護起來的資源或代碼段,其他希望進入臨界區(qū)的線程將被掛起等待,直到擁有臨界區(qū)的線程放棄臨界區(qū)時為止,這樣就保證了不會在同一時刻出現(xiàn)多個線程訪問共享資源。

      CCriticalSection類的用法非常簡單,步驟如下:

      1.定義CCriticalSection類的一個全局對象(以使各個線程均能訪問),如CCriticalSection critical_section;

      2.在訪問需要保護的資源或代碼之前,調(diào)用CCriticalSection類的成員Lock()獲得臨界區(qū)對象: critical_section.Lock();3.在線程中調(diào)用該函數(shù)來使線程獲得它所請求的臨界區(qū)。如果此時沒有其它線程占有臨界區(qū)對象,則調(diào)用Lock()的線程獲得臨界區(qū);否則,線程將被掛起,并放入到一個系統(tǒng)隊列中等待,直到當(dāng)前擁有臨界區(qū)的線程釋放了臨界區(qū)時為止。

      4.訪問臨界區(qū)完畢后,使用CCriticalSection的成員函數(shù)Unlock()來釋放臨界區(qū):critical_section.Unlock();通俗講,就是線程A執(zhí)行到critical_section.Lock();語句時,如果其它線程(B)正在執(zhí)行critical_section.Lock();語句后且critical_section.Unlock();語句前的語句時,線程A就會等待,直到線程B執(zhí)行完critical_section.Unlock();語句,線程A才會繼續(xù)執(zhí)行。

      例程8 MultiThread8 4.3使用 CEvent 類

      CEvent 類提供了對事件的支持。事件是一個允許一個線程在某種情況發(fā)生時,喚醒另外一個線程的同步對象。例如在某些網(wǎng)絡(luò)應(yīng)用程序中,一個線程(記為A)負(fù)責(zé)監(jiān)聽通訊端口,另外一個線程(記為B)負(fù)責(zé)更新用戶數(shù)據(jù)。通過使用CEvent 類,線程A可以通知線程B何時更新用戶數(shù)據(jù)。每一個CEvent 對象可以有兩種狀態(tài):有信號狀態(tài)和無信號狀態(tài)。線程監(jiān)視位于其中的CEvent 類對象的狀態(tài),并在相應(yīng)的時候采取相應(yīng)的操作。

      在MFC中,CEvent 類對象有兩種類型:人工事件和自動事件。一個自動CEvent 對象在被至少一個線程釋放后會自動返回到無信號狀態(tài);而人工事件對象獲得信號后,釋放可利用線程,但直到調(diào)用成員函數(shù)ReSetEvent()才將其設(shè)置為無信號狀態(tài)。在創(chuàng)建CEvent 類的對象時,默認(rèn)創(chuàng)建的是自動事件。CEvent 類的各成員函數(shù)的原型和參數(shù)說明如下:

      1、CEvent(BOOL bInitiallyOwn=FALSE,BOOL bManualReset=FALSE,LPCTSTR lpszName=NULL,LPSECURITY_ATTRIBUTES lpsaAttribute=NULL);bInitiallyOwn:指定事件對象初始化狀態(tài),TRUE為有信號,F(xiàn)ALSE為無信號;

      bManualReset:指定要創(chuàng)建的事件是屬于人工事件還是自動事件。TRUE為人工事件,F(xiàn)ALSE為自動事件;

      后兩個參數(shù)一般設(shè)為NULL,在此不作過多說明。

      2、BOOL CEvent::SetEvent();

      將 CEvent 類對象的狀態(tài)設(shè)置為有信號狀態(tài)。如果事件是人工事件,則 CEvent 類對象保持為有信號狀態(tài),直到調(diào)用成員函數(shù)ResetEvent()將 其重新設(shè)為無信號狀態(tài)時為止。如果CEvent 類對象為自動事件,則在SetEvent()將事件設(shè)置為有信號狀態(tài)后,CEvent 類對象由系統(tǒng)自動重置為無信號狀態(tài)。

      如果該函數(shù)執(zhí)行成功,則返回非零值,否則返回零。

      3、BOOL CEvent::ResetEvent();

      該函數(shù)將事件的狀態(tài)設(shè)置為無信號狀態(tài),并保持該狀態(tài)直至SetEvent()被調(diào)用時為止。由于自動事件是由系統(tǒng)自動重置,故自動事件不需要調(diào)用該函數(shù)。如果該函數(shù)執(zhí)行成功,返回非零值,否則返回零。一般通過調(diào)用WaitForSingleObject函數(shù)來監(jiān)視事件狀態(tài)。前面已經(jīng)介紹了該函數(shù)。由于語言描述的原因,CEvent 類的理解確實有些難度,只要通過下面例程,多看幾遍就可理解。例程9 MultiThread9 仔細(xì)分析這兩個線程函數(shù), 就會正確理解CEvent 類。線程WriteD執(zhí)行到 WaitForSingleObject(eventWriteD.m_hObject,INFINITE);處等待,直到事件eventWriteD為有信號該線程才往下執(zhí)行,因為eventWriteD對象是自動事件,則當(dāng)WaitForSingleObject()返回時,系統(tǒng)自動把eventWriteD對象重置為無信號狀態(tài)。

      4.4使用CMutex 類

      互斥對象與臨界區(qū)對象很像.互斥對象與臨界區(qū)對象的不同在于:互斥對象可以在進程間使用,而臨界區(qū)對象只能在同一進程的各線程間使用。當(dāng)然,互斥對象也可以用于同一進程的各個線程間,但是在這種情況下,使用臨界區(qū)會更節(jié)省系統(tǒng)資源,更有效率。

      4.5使用CSemaphore 類

      當(dāng)需要一個計數(shù)器來限制可以使用某個線程的數(shù)目時,可以使用“信號量”對象。CSemaphore 類的對象保存了對當(dāng)前訪問某一指定資源的線程的計數(shù)值,該計數(shù)值是當(dāng)前還可以使用該資源的線程的數(shù)目。如果這個計數(shù)達到了零,則所有對這個CSemaphore 類對象所控制的資源的訪問嘗試都被放入到一個隊列中等待,直到超時或計數(shù)值不為零時為止。一個線程被釋放已訪問了被保護的資源時,計數(shù)值減1;一個線程完成了對被控共享資源的訪問時,計數(shù)值增1。這個被CSemaphore 類對象所控制的資源可以同時接受訪問的最大線程數(shù)在該對象的構(gòu)建函數(shù)中指定。

      CSemaphore 類的構(gòu)造函數(shù)原型及參數(shù)說明如下:

      CSemaphore(LONG lInitialCount=1,LONG lMaxCount=1,LPCTSTR pstrName=NULL,LPSECURITY_ATTRIBUTES lpsaAttributes=NULL);lInitialCount:信號量對象的初始計數(shù)值,即可訪問線程數(shù)目的初始值;

      lMaxCount:信號量對象計數(shù)值的最大值,該參數(shù)決定了同一時刻可訪問由信號量保護的資源的線程最大數(shù)目;

      后兩個參數(shù)在同一進程中使用一般為NULL,不作過多討論;

      在用CSemaphore 類的構(gòu)造函數(shù)創(chuàng)建信號量對象時要同時指出允許的最大資源計數(shù)和當(dāng)前可用資源計數(shù)。一般是將當(dāng)前可用資源計數(shù)設(shè)置為最大資源計數(shù),每增加一個線程對共享資源的訪問,當(dāng)前可用資源計數(shù)就會減1,只要當(dāng)前可用資源計數(shù)是大于0的,就可以發(fā)出信號量信號。但是當(dāng)前可用計數(shù)減小到0時,則說明當(dāng)前占用資源的線程數(shù)已經(jīng)達到了所允許的最大數(shù)目,不能再允許其它線程的進入,此時的信號量信號將無法發(fā)出。線程在處理完共享資源后,應(yīng)在離開的同時通過ReleaseSemaphore()函數(shù)將當(dāng)前可用資源數(shù)加1。例程10 MultiThread10 為了文件中能夠正確使用同步類,在文件開頭添加: #include “afxmt.h” 定義信號量對象和一個字符數(shù)組,為了能夠在不同線程間使用,定義為全局變量:CSemaphore semaphoreWrite(2,2);//資源最多訪問線程2個,當(dāng)前可訪問線程數(shù)2個

      在信號量對象有信號的狀態(tài)下,線程執(zhí)行到WaitForSingleObject語句處繼續(xù)執(zhí)行,同時可用線程數(shù)減1;若線程執(zhí)行到WaitForSingleObject語句時信號量對象無信號,線程就在這里等待,直到信號量對象有信號線程才往下執(zhí)行。

      第二篇:Java多線程編程總結(jié)

      Java多線程編程總結(jié)

      2007-05-17 11:21:59 標(biāo)簽:java 多線程

      原創(chuàng)作品,允許轉(zhuǎn)載,轉(zhuǎn)載時請務(wù)必以超鏈接形式標(biāo)明文章 原始出處、作者信息和本聲明。否則將追究法律責(zé)任。http://lavasoft.blog.51cto.com/62575/27069

      Java多線程編程總結(jié)

      下面是Java線程系列博文的一個編目:

      Java線程:概念與原理 Java線程:創(chuàng)建與啟動

      Java線程:線程棧模型與線程的變量 Java線程:線程狀態(tài)的轉(zhuǎn)換 Java線程:線程的同步與鎖 Java線程:線程的交互 Java線程:線程的調(diào)度-休眠 Java線程:線程的調(diào)度-優(yōu)先級 Java線程:線程的調(diào)度-讓步 Java線程:線程的調(diào)度-合并 Java線程:線程的調(diào)度-守護線程 Java線程:線程的同步-同步方法 Java線程:線程的同步-同步塊

      Java線程:并發(fā)協(xié)作-生產(chǎn)者消費者模型 Java線程:并發(fā)協(xié)作-死鎖 Java線程:volatile關(guān)鍵字 Java線程:新特征-線程池

      Java線程:新特征-有返回值的線程 Java線程:新特征-鎖(上)Java線程:新特征-鎖(下)Java線程:新特征-信號量 Java線程:新特征-阻塞隊列 Java線程:新特征-阻塞棧 Java線程:新特征-條件變量 Java線程:新特征-原子量 Java線程:新特征-障礙器 Java線程:大總結(jié)

      ----

      下面的內(nèi)容是很早之前寫的,內(nèi)容不夠充實,而且是基于Java1.4的內(nèi)容,Java5之后,線程并發(fā)部分?jǐn)U展了相當(dāng)多的內(nèi)容,因此建議大家看上面的系列文章的內(nèi)容,與時俱進,跟上Java發(fā)展的步伐。----

      一、認(rèn)識多任務(wù)、多進程、單線程、多線程 要認(rèn)識多線程就要從操作系統(tǒng)的原理說起。

      以前古老的DOS操作系統(tǒng)(V 6.22)是單任務(wù)的,還沒有線程的概念,系統(tǒng)在每次只能做一件事情。比如你在copy東西的時候不能rename文件名。為了提高系統(tǒng)的利用效率,采用批處理來批量執(zhí)行任務(wù)。

      現(xiàn)在的操作系統(tǒng)都是多任務(wù)操作系統(tǒng),每個運行的任務(wù)就是操作系統(tǒng)所做的一件事情,比如你在聽歌的同時還在用MSN和好友聊天。聽歌和聊天就是兩個任務(wù),這個兩個任務(wù)是“同時”進行的。一個任務(wù)一般對應(yīng)一個進程,也可能包含好幾個進程。比如運行的MSN就對應(yīng)一個MSN的進程,如果你用的是windows系統(tǒng),你就可以在任務(wù)管理器中看到操作系統(tǒng)正在運行的進程信息。

      一般來說,當(dāng)運行一個應(yīng)用程序的時候,就啟動了一個進程,當(dāng)然有些會啟動多個進程。啟動進程的時候,操作系統(tǒng)會為進程分配資源,其中最主要的資源是內(nèi)存空間,因為程序是在內(nèi)存中運行的。在進程中,有些程序流程塊是可以亂序執(zhí)行的,并且這個代碼塊可以同時被多次執(zhí)行。實際上,這樣的代碼塊就是線程體。線程是進程中亂序執(zhí)行的代碼流程。當(dāng)多個線程同時運行的時候,這樣的執(zhí)行模式成為并發(fā)執(zhí)行。

      多線程的目的是為了最大限度的利用CPU資源。

      Java編寫程序都運行在在Java虛擬機(JVM)中,在JVM的內(nèi)部,程序的多任務(wù)是通過線程來實現(xiàn)的。每用java命令啟動一個java應(yīng)用程序,就會啟動一個JVM進程。在同一個JVM進程中,有且只有一個進程,就是它自己。在這個JVM環(huán)境中,所有程序代碼的運行都是以線程來運行。

      一般常見的Java應(yīng)用程序都是單線程的。比如,用java命令運行一個最簡單的HelloWorld的Java應(yīng)用程序時,就啟動了一個JVM進程,JVM找到程序程序的入口點main(),然后運行main()方法,這樣就產(chǎn)生了一個線程,這個線程稱之為主線程。當(dāng)main方法結(jié)束后,主線程運行完成。JVM進程也隨即退出。

      對于一個進程中的多個線程來說,多個線程共享進程的內(nèi)存塊,當(dāng)有新的線程產(chǎn)生的時候,操作系統(tǒng)不分配新的內(nèi)存,而是讓新線程共享原有的進程塊的內(nèi)存。因此,線程間的通信很容易,速度也很快。不同的進程因為處于不同的內(nèi)存塊,因此進程之間的通信相對困難。

      實際上,操作的系統(tǒng)的多進程實現(xiàn)了多任務(wù)并發(fā)執(zhí)行,程序的多線程實現(xiàn)了進程的并發(fā)執(zhí)行。多任務(wù)、多進程、多線程的前提都是要求操作系統(tǒng)提供多任務(wù)、多進程、多線程的支持。

      在Java程序中,JVM負(fù)責(zé)線程的調(diào)度。線程調(diào)度是值按照特定的機制為多個線程分配CPU的使用權(quán)。調(diào)度的模式有兩種:分時調(diào)度和搶占式調(diào)度。分時調(diào)度是所有線程輪流獲得CPU使用權(quán),并平均分配每個線程占用CPU的時間;搶占式調(diào)度是根據(jù)線程的優(yōu)先級別來獲取CPU的使用權(quán)。JVM的線程調(diào)度模式采用了搶占式模式。

      所謂的“并發(fā)執(zhí)行”、“同時”其實都不是真正意義上的“同時”。眾所周知,CPU都有個時鐘頻率,表示每秒中能執(zhí)行cpu指令的次數(shù)。在每個時鐘周期內(nèi),CPU實際上只能去執(zhí)行一條(也有可能多條)指令。操作系統(tǒng)將進程線程進行管理,輪流(沒有固定的順序)分配每個進程很短的一段是時間(不一定是均分),然后在每個線程內(nèi)部,程序代碼自己處理該進程內(nèi)部線程的時間分配,多個線程之間相互的切換去執(zhí)行,這個切換時間也是非常短的。因此多任務(wù)、多進程、多線程都是操作系統(tǒng)給人的一種宏觀感受,從微觀角度看,程序的運行是異步執(zhí)行的。

      用一句話做總結(jié):雖然操作系統(tǒng)是多線程的,但CPU每一時刻只能做一件事,和人的大腦是一樣的,呵呵。

      二、Java與多線程

      Java語言的多線程需要操作系統(tǒng)的支持。

      Java 虛擬機允許應(yīng)用程序并發(fā)地運行多個執(zhí)行線程。Java語言提供了多線程編程的擴展點,并給出了功能強大的線程控制API。

      在Java中,多線程的實現(xiàn)有兩種方式: 擴展java.lang.Thread類 實現(xiàn)java.lang.Runnable接口

      每個線程都有一個優(yōu)先級,高優(yōu)先級線程的執(zhí)行優(yōu)先于低優(yōu)先級線程。每個線程都可以或不可以標(biāo)記為一個守護程序。當(dāng)某個線程中運行的代碼創(chuàng)建一個新 Thread 對象時,該新線程的初始優(yōu)先級被設(shè)定為創(chuàng)建線程的優(yōu)先級,并且當(dāng)且僅當(dāng)創(chuàng)建線程是守護線程時,新線程才是守護程序。

      當(dāng) Java 虛擬機啟動時,通常都會有單個非守護線程(它通常會調(diào)用某個指定類的 main 方法)。Java 虛擬機會繼續(xù)執(zhí)行線程,直到下列任一情況出現(xiàn)時為止:

      調(diào)用了 Runtime 類的 exit 方法,并且安全管理器允許退出操作發(fā)生。

      非守護線程的所有線程都已停止運行,無論是通過從對 run 方法的調(diào)用中返回,還是通過拋出一個傳播到 run 方法之外的異常。

      三、擴展java.lang.Thread類

      /** * File Name: TestMitiThread.java * Created by: IntelliJ IDEA.* Copyright: Copyright(c)2003-2006 * Company: Lavasoft([url]http://lavasoft.blog.51cto.com/[/url])* Author: leizhimin * Modifier: leizhimin * Date Time: 2007-5-17 10:03:12 * Readme: 通過擴展Thread類實現(xiàn)多線程 */ public class TestMitiThread { public static void main(String[] rags){ System.out.println(Thread.currentThread().getName()+ “ 線程運行開始!”);new MitiSay(“A”).start();new MitiSay(“B”).start();System.out.println(Thread.currentThread().getName()+ “ 線程運行結(jié)束!”);} }

      class MitiSay extends Thread { public MitiSay(String threadName){ super(threadName);}

      public void run(){ System.out.println(getName()+ “ 線程運行開始!”);for(int i = 0;i < 10;i++){ System.out.println(i + “ ” + getName());try { sleep((int)Math.random()* 10);} catch(InterruptedException e){ e.printStackTrace();} } System.out.println(getName()+ “ 線程運行結(jié)束!”);} }

      運行結(jié)果:

      main 線程運行開始!main 線程運行結(jié)束!A 線程運行開始!0 A 1 A B 線程運行開始!2 A 0 B 3 A 4 A 1 B 5 A 6 A 7 A 8 A 9 A A 線程運行結(jié)束!2 B 3 B 4 B 5 B 6 B 7 B 8 B 9 B B 線程運行結(jié)束!說明:

      程序啟動運行main時候,java虛擬機啟動一個進程,主線程main在main()調(diào)用時候被創(chuàng)建。隨著調(diào)用MitiSay的兩個對象的start方法,另外兩個線程也啟動了,這樣,整個應(yīng)用就在多線程下運行。

      在一個方法中調(diào)用Thread.currentThread().getName()方法,可以獲取當(dāng)前線程的名字。在mian方法中調(diào)用該方法,獲取的是主線程的名字。

      注意:start()方法的調(diào)用后并不是立即執(zhí)行多線程代碼,而是使得該線程變?yōu)榭蛇\行態(tài)(Runnable),什么時候運行是由操作系統(tǒng)決定的。

      從程序運行的結(jié)果可以發(fā)現(xiàn),多線程程序是亂序執(zhí)行。因此,只有亂序執(zhí)行的代碼才有必要設(shè)計為多線程。

      Thread.sleep()方法調(diào)用目的是不讓當(dāng)前線程獨自霸占該進程所獲取的CPU資源,以留出一定時間給其他線程執(zhí)行的機會。

      實際上所有的多線程代碼執(zhí)行順序都是不確定的,每次執(zhí)行的結(jié)果都是隨機的。

      四、實現(xiàn)java.lang.Runnable接口

      /** * 通過實現(xiàn) Runnable 接口實現(xiàn)多線程 */ public class TestMitiThread1 implements Runnable {

      public static void main(String[] args){ System.out.println(Thread.currentThread().getName()+ “ 線程運行開始!”);TestMitiThread1 test = new TestMitiThread1();Thread thread1 = new Thread(test);Thread thread2 = new Thread(test);thread1.start();thread2.start();System.out.println(Thread.currentThread().getName()+ “ 線程運行結(jié)束!”);}

      public void run(){ System.out.println(Thread.currentThread().getName()+ “ 線程運行開始!”);for(int i = 0;i < 10;i++){ System.out.println(i + “ ” + Thread.currentThread().getName());try { Thread.sleep((int)Math.random()* 10);} catch(InterruptedException e){ e.printStackTrace();} } System.out.println(Thread.currentThread().getName()+ “ 線程運行結(jié)束!”);} }

      運行結(jié)果:

      main 線程運行開始!Thread-0 線程運行開始!main 線程運行結(jié)束!0 Thread-0 Thread-1 線程運行開始!0 Thread-1 1 Thread-1 1 Thread-0 2 Thread-0 2 Thread-1 3 Thread-0 3 Thread-1 4 Thread-0 4 Thread-1 5 Thread-0 6 Thread-0 5 Thread-1 7 Thread-0 8 Thread-0 6 Thread-1 9 Thread-0 7 Thread-1 Thread-0 線程運行結(jié)束!8 Thread-1 9 Thread-1 Thread-1 線程運行結(jié)束!說明:

      TestMitiThread1類通過實現(xiàn)Runnable接口,使得該類有了多線程類的特征。run()方法是多線程程序的一個約定。所有的多線程代碼都在run方法里面。Thread類實際上也是實現(xiàn)了Runnable接口的類。

      在啟動的多線程的時候,需要先通過Thread類的構(gòu)造方法Thread(Runnable target)構(gòu)造出對象,然后調(diào)用Thread對象的start()方法來運行多線程代碼。

      實際上所有的多線程代碼都是通過運行Thread的start()方法來運行的。因此,不管是擴展Thread類還是實現(xiàn)Runnable接口來實現(xiàn)多線程,最終還是通過Thread的對象的API來控制線程的,熟悉Thread類的API是進行多線程編程的基礎(chǔ)。

      五、讀解Thread類API

      static int MAX_PRIORITY 線程可以具有的最高優(yōu)先級。static int MIN_PRIORITY 線程可以具有的最低優(yōu)先級。static int NORM_PRIORITY 分配給線程的默認(rèn)優(yōu)先級。

      構(gòu)造方法摘要

      Thread(Runnable target)分配新的 Thread 對象。Thread(String name)分配新的 Thread 對象。

      方法摘要

      static Thread currentThread()返回對當(dāng)前正在執(zhí)行的線程對象的引用。ClassLoader getContextClassLoader()返回該線程的上下文 ClassLoader。long getId()返回該線程的標(biāo)識符。String getName()返回該線程的名稱。int getPriority()返回線程的優(yōu)先級。Thread.State getState()返回該線程的狀態(tài)。ThreadGroup getThreadGroup()返回該線程所屬的線程組。static boolean holdsLock(Object obj)當(dāng)且僅當(dāng)當(dāng)前線程在指定的對象上保持監(jiān)視器鎖時,才返回 true。void interrupt()中斷線程。

      static boolean interrupted()測試當(dāng)前線程是否已經(jīng)中斷。boolean isAlive()測試線程是否處于活動狀態(tài)。boolean isDaemon()測試該線程是否為守護線程。boolean isInterrupted()測試線程是否已經(jīng)中斷。void join()等待該線程終止。void join(long millis)等待該線程終止的時間最長為 millis 毫秒。void join(long millis, int nanos)等待該線程終止的時間最長為 millis 毫秒 + nanos 納秒。void resume()已過時。該方法只與 suspend()一起使用,但 suspend()已經(jīng)遭到反對,因為它具有死鎖傾向。有關(guān)更多信息,請參閱為何 Thread.stop、Thread.suspend 和 Thread.resume 遭到反對?。void run()如果該線程是使用獨立的 Runnable 運行對象構(gòu)造的,則調(diào)用該 Runnable 對象的 run 方法;否則,該方法不執(zhí)行任何操作并返回。void setContextClassLoader(ClassLoader cl)設(shè)置該線程的上下文 ClassLoader。void setDaemon(boolean on)將該線程標(biāo)記為守護線程或用戶線程。

      static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)設(shè)置當(dāng)線程由于未捕獲到異常而突然終止,并且沒有為該線程定義其他處理程序時所調(diào)用的默認(rèn)處理程序。void setName(String name)改變線程名稱,使之與參數(shù) name 相同。void setPriority(int newPriority)更改線程的優(yōu)先級。

      void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)設(shè)置該線程由于未捕獲到異常而突然終止時調(diào)用的處理程序。static void sleep(long millis)在指定的毫秒數(shù)內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠(暫停執(zhí)行)。static void sleep(long millis, int nanos)在指定的毫秒數(shù)加指定的納秒數(shù)內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠(暫停執(zhí)行)。void start()使該線程開始執(zhí)行;Java 虛擬機調(diào)用該線程的 run 方法。void stop()已過時。該方法具有固有的不安全性。用 Thread.stop 來終止線程將釋放它已經(jīng)鎖定的所有監(jiān)視器(作為沿堆棧向上傳播的未檢查 ThreadDeath 異常的一個自然后果)。如果以前受這些監(jiān)視器保護的任何對象都處于一種不一致的狀態(tài),則損壞的對象將對其他線程可見,這有可能導(dǎo)致任意的行為。stop 的許多使用都應(yīng)由只修改某些變量以指示目標(biāo)線程應(yīng)該停止運行的代碼來取代。目標(biāo)線程應(yīng)定期檢查該變量,并且如果該變量指示它要停止運行,則從其運行方法依次返回。如果目標(biāo)線程等待很長時間(例如基于一個條件變量),則應(yīng)使用 interrupt 方法來中斷該等待。有關(guān)更多信息,請參閱《為何不贊成使用 Thread.stop、Thread.suspend 和 Thread.resume?》。void stop(Throwable obj)已過時。該方法具有固有的不安全性。請參閱 stop()以獲得詳細(xì)信息。該方法的附加危險是它可用于生成目標(biāo)線程未準(zhǔn)備處理的異常(包括若沒有該方法該線程不太可能拋出的已檢查的異常)。有關(guān)更多信息,請參閱為何 Thread.stop、Thread.suspend 和 Thread.resume 遭到反對?。void suspend()已過時。該方法已經(jīng)遭到反對,因為它具有固有的死鎖傾向。如果目標(biāo)線程掛起時在保護關(guān)鍵系統(tǒng)資源的監(jiān)視器上保持有鎖,則在目標(biāo)線程重新開始以前任何線程都不能訪問該資源。如果重新開始目標(biāo)線程的線程想在調(diào)用 resume 之前鎖定該監(jiān)視器,則會發(fā)生死鎖。這類死鎖通常會證明自己是“凍結(jié)”的進程。有關(guān)更多信息,請參閱為何 Thread.stop、Thread.suspend 和 Thread.resume 遭到反對?。String toString()返回該線程的字符串表示形式,包括線程名稱、優(yōu)先級和線程組。static void yield()暫停當(dāng)前正在執(zhí)行的線程對象,并執(zhí)行其他線程。

      六、線程的狀態(tài)轉(zhuǎn)換圖

      線程在一定條件下,狀態(tài)會發(fā)生變化。線程變化的狀態(tài)轉(zhuǎn)換圖如下:

      1、新建狀態(tài)(New):新創(chuàng)建了一個線程對象。

      2、就緒狀態(tài)(Runnable):線程對象創(chuàng)建后,其他線程調(diào)用了該對象的start()方法。該狀態(tài)的線程位于可運行線程池中,變得可運行,等待獲取CPU的使用權(quán)。

      3、運行狀態(tài)(Running):就緒狀態(tài)的線程獲取了CPU,執(zhí)行程序代碼。

      4、阻塞狀態(tài)(Blocked):阻塞狀態(tài)是線程因為某種原因放棄CPU使用權(quán),暫時停止運行。直到線程進入就緒狀態(tài),才有機會轉(zhuǎn)到運行狀態(tài)。阻塞的情況分三種:

      (一)、等待阻塞:運行的線程執(zhí)行wait()方法,JVM會把該線程放入等待池中。

      (二)、同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程占用,則JVM會把該線程放入鎖池中。

      (三)、其他阻塞:運行的線程執(zhí)行sleep()或join()方法,或者發(fā)出了I/O請求時,JVM會把該線程置為阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉(zhuǎn)入就緒狀態(tài)。

      5、死亡狀態(tài)(Dead):線程執(zhí)行完了或者因異常退出了run()方法,該線程結(jié)束生命周期。

      七、線程的調(diào)度

      1、調(diào)整線程優(yōu)先級:Java線程有優(yōu)先級,優(yōu)先級高的線程會獲得較多的運行機會。

      Java線程的優(yōu)先級用整數(shù)表示,取值范圍是1~10,Thread類有以下三個靜態(tài)常量: static int MAX_PRIORITY 線程可以具有的最高優(yōu)先級,取值為10。static int MIN_PRIORITY 線程可以具有的最低優(yōu)先級,取值為1。static int NORM_PRIORITY 分配給線程的默認(rèn)優(yōu)先級,取值為5。

      Thread類的setPriority()和getPriority()方法分別用來設(shè)置和獲取線程的優(yōu)先級。

      每個線程都有默認(rèn)的優(yōu)先級。主線程的默認(rèn)優(yōu)先級為Thread.NORM_PRIORITY。

      線程的優(yōu)先級有繼承關(guān)系,比如A線程中創(chuàng)建了B線程,那么B將和A具有相同的優(yōu)先級。JVM提供了10個線程優(yōu)先級,但與常見的操作系統(tǒng)都不能很好的映射。如果希望程序能移植到各個操作系統(tǒng)中,應(yīng)該僅僅使用Thread類有以下三個靜態(tài)常量作為優(yōu)先級,這樣能保證同樣的優(yōu)先級采用了同樣的調(diào)度方式。

      2、線程睡眠:Thread.sleep(long millis)方法,使線程轉(zhuǎn)到阻塞狀態(tài)。millis參數(shù)設(shè)定睡眠的時間,以毫秒為單位。當(dāng)睡眠結(jié)束后,就轉(zhuǎn)為就緒(Runnable)狀態(tài)。sleep()平臺移植性好。

      3、線程等待:Object類中的wait()方法,導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對象的 notify()方法或 notifyAll()喚醒方法。這個兩個喚醒方法也是Object類中的方法,行為等價于調(diào)用 wait(0)一樣。

      4、線程讓步:Thread.yield()方法,暫停當(dāng)前正在執(zhí)行的線程對象,把執(zhí)行機會讓給相同或者更高優(yōu)先級的線程。

      5、線程加入:join()方法,等待其他線程終止。在當(dāng)前線程中調(diào)用另一個線程的join()方法,則當(dāng)前線程轉(zhuǎn)入阻塞狀態(tài),直到另一個進程運行結(jié)束,當(dāng)前線程再由阻塞轉(zhuǎn)為就緒狀態(tài)。

      6、線程喚醒:Object類中的notify()方法,喚醒在此對象監(jiān)視器上等待的單個線程。如果所有線程都在此對象上等待,則會選擇喚醒其中一個線程。選擇是任意性的,并在對實現(xiàn)做出決定時發(fā)生。線程通過調(diào)用其中一個 wait 方法,在對象的監(jiān)視器上等待。直到當(dāng)前的線程放棄此對象上的鎖定,才能繼續(xù)執(zhí)行被喚醒的線程。被喚醒的線程將以常規(guī)方式與在該對象上主動同步的其他所有線程進行競爭;例如,喚醒的線程在作為鎖定此對象的下一個線程方面沒有可靠的特權(quán)或劣勢。類似的方法還有一個notifyAll(),喚醒在此對象監(jiān)視器上等待的所有線程。注意:Thread中suspend()和resume()兩個方法在JDK1.5中已經(jīng)廢除,不再介紹。因為有死鎖傾向。

      7、常見線程名詞解釋

      主線程:JVM調(diào)用程序mian()所產(chǎn)生的線程。

      當(dāng)前線程:這個是容易混淆的概念。一般指通過Thread.currentThread()來獲取的進程。后臺線程:指為其他線程提供服務(wù)的線程,也稱為守護線程。JVM的垃圾回收線程就是一個后臺線程。

      前臺線程:是指接受后臺線程服務(wù)的線程,其實前臺后臺線程是聯(lián)系在一起,就像傀儡和幕后操縱者一樣的關(guān)系??苁乔芭_線程、幕后操縱者是后臺線程。由前臺線程創(chuàng)建的線程默認(rèn)也是前臺線程??梢酝ㄟ^isDaemon()和setDaemon()方法來判斷和設(shè)置一個線程是否為后臺線程。

      本文出自 “熔 巖” 博客,請務(wù)必保留此出處http://lavasoft.blog.51cto.com/62575/27069

      第三篇:C++編程知識總結(jié)

      1.數(shù)組

      1.1數(shù)組定義時的注意點

      1在C++中不提供可變化大小的數(shù)組,○即數(shù)組定義中的常量表達式不能包含變量。(來源:C++書6.1.1)

      int n;cin>>n;float t[n];上例在定義數(shù)組t時,變量n沒有確定的值,即在程序執(zhí)行之前,無法知道數(shù)組t的元素個數(shù),所以這種聲明不被允許。但是可以用new動態(tài)分配,如: int n;cin>>n;float *t;t=new float[n];

      2在定義數(shù)組時,可以不直接指定數(shù)組的大小,由C++編譯器根據(jù)初值表中元素的個數(shù)來自○動確定數(shù)組元素的個數(shù)。例如: int z[]={0,1,2,3,4,5,6,7,8} 3C++語言規(guī)定只能對數(shù)組中的元素進行賦值或引用,不能把整個數(shù)組作為一個整體進行賦○值或引用。(2.3是一個實例)(來源:C++書4同類型的數(shù)組之間不能相互賦值 ○如int a[5],b[5];a=b;//錯誤

      strcpy(b,a);//正確

      6.1.1)

      1.2數(shù)組和指針的關(guān)系(來源:C++書8.2節(jié)8.2.1)

      char s[5];在C++中說明了一個數(shù)組后,數(shù)組名可以作為一個指針來使用,因此s可作為一個指針使用(但它不同于指針,不能賦值運算、算術(shù)運算等)。

      2.字符數(shù)組

      2.1輸入字符數(shù)據(jù) char c;cin>>c;// cin不能將輸入的空格賦給字符型變量。

      cin.get();//可獲得鍵盤上輸入的每一個字符,包括空格和回車鍵。

      2.2字符數(shù)組的輸入/輸出(來源:C++書6.2.4)2.2.1逐個字符輸入 char c[10];for(int i=0;i<10;i++)cin>>c[i];2.2.2字符串輸入 方法1 char c[10];cin>>c;//即在輸入輸出時只給數(shù)組名

      此法在輸入字符串時,遇到空格和回車就認(rèn)為一個字符結(jié)束。方法2 cin.getline(字符數(shù)組名,允許輸入的最大字符個數(shù))此法可把輸入的一行作為一個字符串送到字符數(shù)組中。

      2.3字符數(shù)組和字符指針的初始化 2.3.1字符數(shù)組初始化 char tx[5]=“";2.3.2字符指針初始化 char *ptx=new char[5];ptx[0]='