在线观看国产免费视频_亚洲视频三区_中文字幕在线观看网站_日韩视频免费在线观看_亚洲视频精品_天天夜夜操

當前位置:網站首頁 >> 作文 >> Java 多線程編程(五篇)

Java 多線程編程(五篇)

格式:DOC 上傳日期:2024-08-22 23:41:33
Java 多線程編程(五篇)
時間:2024-08-22 23:41:33     小編:zdfb

在日常的學習、工作、生活中,肯定對各類范文都很熟悉吧。范文書寫有哪些要求呢?我們怎樣才能寫好一篇范文呢?這里我整理了一些優秀的范文,希望對大家有所幫助,下面我們就來了解一下吧。

Java 多線程編程篇一

一、問題的提出

1.1問題的引出

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

新建一個基于對話框的應用程序singlethread,在主對話框idd_singlethread_dialog添加一個按鈕,id為idc_sleep_six_second,標題為“延時6秒”,添加按鈕的響應函數,代碼如下:

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

1.2多線程概述

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

線程是進程內部的一個執行單元。系統創建好進程后,實際上就啟動執行了該進程的主執行線程,主執行線程以函數地址形式,比如說main或winmain函數,將程序的啟動點提供給windows系統。主執行線程終止了,進程也就隨之終止。

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

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

win32 sdk函數支持進行多線程的程序設計,并提供了操作系統原理中的各種同步、互斥和臨界區等操作。visual c++中,使用mfc類庫也實現了多線程的程序設計,使得多線程編程更加方便。1.3 win32 api對多線程編程的支持

win32 提供了一系列的api函數來完成線程的創建、掛起、恢復、終結以及通信等工作。下面將選取其中的一些重要函數進行說明。

1、handle createthread(lpsecurity_attributes lpthreadattributes,dword dwstacksize,lpthread_start_routine lpstartaddress,lpvoid lpparameter,dword dwcreationflags,lpdword lpthreadid);該函數在其調用進程的進程空間里創建一個新的線程,并返回已建線程的句柄,其中各參數說明如下:

lpthreadattributes:指向一個 security_attributes 結構的指針,該結構決定了線程的安全屬性,一般置為 null;

dwstacksize:指定了線程的堆棧深度,一般都設置為0;

lpstartaddress:表示新線程開始執行時代碼所在函數的地址,即線程的起始地址。一般情況為(lpthread_start_routine)threadfunc,threadfunc 是線程函數名;

lpparameter:指定了線程執行時傳送給線程的32位參數,即線程函數的參數;

dwcreationflags:控制線程創建的附加標志,可以取兩種值。如果該參數為0,線程在被創建后就會立即開始執行;如果該參數為create_suspended,則系統產生線程后,該線程處于掛起狀態,并不馬上執行,直至函數resumethread被調用;

lpthreadid:該參數返回所創建線程的id;

如果創建成功則返回線程的句柄,否則返回null。

2、dword suspendthread(handle hthread);該函數用于掛起指定的線程,如果函數執行成功,則線程的執行被終止。

3、dword resumethread(handle hthread);該函數用于結束線程的掛起狀態,執行線程。

4、void exitthread(dword dwexitcode);該函數用于線程終結自身的執行,主要在線程的執行函數中被調用。其中參數dwexitcode用來設置線程的退出碼。

5、bool terminatethread(handle hthread,dword dwexitcode);

一般情況下,線程運行結束之后,線程函數正常返回,但是應用程序可以調用terminatethread強行終止某一線程的執行。各參數含義如下: hthread:將被終結的線程的句柄;

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

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

6、bool postthreadmessage(dword idthread,uint msg,wparam wparam,lparam lparam);該函數將一條消息放入到指定線程的消息隊列中,并且不等到消息被該線程處理時便返回。idthread:將接收消息的線程的id;

msg:指定用來發送的消息;

wparam:同消息有關的字參數;

lparam:同消息有關的長參數;

調用該函數時,如果即將接收消息的線程沒有創建消息循環,則該函數執行失敗。

32 api多線程編程例程

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

? volatile:關鍵字:

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

如從串口讀數據的場合,把變量緩沖在寄存器里,le也加上,以保證從內存中讀取變量的值.? 終止線程:

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

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

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

? 通過調用 exitthread 函數,線程將自行撤消(最好不要使用這種方法)。

? 同一個進程或另一個進程中的線程調用 terminatethread 函數(應該避免使用這種方法)。

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

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

? 線程函數返回

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

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

? 在線程函數中創建的所有 c++ 對象均將通過它們的撤消函數正確地撤消。

? 操作系統將正確地釋放線程堆棧使用的內存。

? 系統將線程的退出代碼(在線程的內核對象中維護)設置為線程函數的返回值。

? 系統將遞減線程內核對象的使用計數。? 使用 exitthread 函數

可以讓線程調用 exitthread 函數,以便強制線程終止運行:

void exitthread(dword dwexitcode);

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

當然,可以使用 exitthread 的 dwexitthread 參數告訴系統將線程的退出代碼設置為什么。exitthread 函數并不返回任何值,因為線程已經終止運行,不能執行更多的代碼。? 使用 terminatethread 函數

調用 terminatethread 函數也能夠終止線程的運行:

bool terminatethread(handle hthread, dword dwexitcode);

與 exitthread 不同,exitthread 總是撤消調用的線程,而 terminatethread 能夠撤消任何線程。hthread 參數用于標識被終止運行的線程的句柄。當線程終止運行時,它的退出代碼成為你作為 dwexitcode 參數傳遞的值。同時,線程的內核對象的使用計數也被遞減。

注意 terminatethread 函數是異步運行的函數,也就是說,它告訴系統你想要線程終止運行,但是,當函數返回時,不能保證線程被撤消。如果需要確切地知道該線程已經終止運行,必須調用 waitforsingleobject 或者類似的函數,傳遞線程的句柄。

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

注意 當使用返回或調用 exitthread 的方法撤消線程時,該線程的內存堆棧也被撤消。但是,如果使用 terminatethread,那么在擁有線程的進程終止運行之前,系統不撤消該線程的堆棧。microsoft故意用這種方法來實現 terminatethread。如果其他仍然正在執行的線程要引用強制撤消的線程堆棧上的值,那么其他的線程就會出現訪問違規的問題。如果將已經撤消的線程的堆棧留在內存中,那么其他線程就可以繼續很好地運行。

此外,當線程終止運行時,dll 通常接收通知。如果使用 terminatethread 強迫線程終止,dll 就不接收通知,這能阻止適當的清除,在進程終止運行時撤消線程。當線程終止運行時,會發生下列操作:

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

? 線程的退出代碼從 still_active 改為傳遞給 exitthread 或 terminatethread 的代碼。

? 線程內核對象的狀態變為已通知。

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

? 線程內核對象的使用計數遞減 1。

當一個線程終止運行時,在與它相關聯的線程內核對象的所有未結束的引用關閉之前,該內核對象不會自動被釋放。

一旦線程不再運行,系統中就沒有別的線程能夠處理該線程的句柄。然而別的線程可以調用 getexitcodethread 來檢查由 hthread 標識的線程是否已經終止運行。如果它已經終止運行,則確定它的退出代碼:

bool getexitcodethread(handle hthread, pdowrd pdwexitcode);退出代碼的值在 pdwexitcode 指向的 dword 中返回。如果調用 getexitcodethread 時線程尚未終止運行,該函數就用 still_active 標識符(定義為 0x103)填入 dword。如果該函數運行成功,便返回 true。

? 線程的定義:

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

dword waitforsingleobject(handle hhandle,dword dwmilliseconds);

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

dwmilliseconds:為hhandle對象所設置的超時值,單位為毫秒;

當在某一線程中調用該函數時,線程暫時掛起,系統監視hhandle所指向的對象的狀態。如果在掛起的dwmilliseconds毫秒內,線程所等待的對象變為有信號狀態,則該函數立即返回;如果超時時間已經到達dwmilliseconds毫秒,但hhandle所指向的對象還沒有變成有信號狀態,函數照樣返回。參數dwmilliseconds有兩個具有特殊意義的值:0和infinite。若為0,則該函數立即返回;若為infinite,則線程一直被掛起,直到hhandle所指向的對象變為有信號狀態時為止。

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

例程4[multithread4] 測試在windows下最多可創建線程的數目。

二、mfc中的多線程開發

2.1 mfc對多線程編程的支持

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

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

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

(1)cwinthread* afxbeginthread(afx_threadproc pfnthreadproc,lpvoid pparam,npriority=thread_priority_normal,uint nstacksize=0,dword dwcreateflags=0,lpsecurity_attributes lpsecurityattrs=null);

pfnthreadproc:指向工作者線程的執行函數的指針,線程函數原型必須聲明如下: uint executingfunction(lpvoid pparam);請注意,executingfunction()應返回一個uint類型的值,用以指明該函數結束的原因。一般情況下,返回0表明執行成功。

pparam:傳遞給線程函數的一個32位參數,執行函數將用某種方式解釋該值。它可以是數值,或是指向一個結構的指針,甚至可以被忽略;

npriority:線程的優先級。如果為0,則線程與其父線程具有相同的優先級;

nstacksize:線程為自己分配堆棧的大小,其單位為字節。如果nstacksize被設為0,則線程的堆棧被設置成與父線程堆棧相同大小; dwcreateflags:如果為0,則線程在創建后立刻開始執行。如果為create_suspend,則線程在創建后立刻被掛起;

lpsecurityattrs:線程的安全屬性指針,一般為null;

(2)cwinthread* afxbeginthread(cruntimeclass* pthreadclass,int npriority=thread_priority_normal,uint nstacksize=0,dword dwcreateflags=0,lpsecurity_attributes lpsecurityattrs=null);

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

? ? ? m_hthread:當前線程的句柄;

m_nthreadid:當前線程的id;

m_pmainwnd:指向應用程序主窗口的指針

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

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

2.2 mfc多線程編程實例

例程5 multithread5 為了與win32 api對照,使用mfc 類庫編程實現例程3 multithread3。

例程6 multithread6[用戶界面線程] ? 創建用戶界面線程的步驟:

1.使用classwizard創建類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.重載函數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.創建新的用戶界面線程 void cuithreaddlg::onbutton1(){

}

請注意以下兩點:

a、的開頭加入語句: #include “uithread.h” b、把uithread.h中類cuithread()的構造函數的特性由 protected 改為 public。cuithread* pthread=new cuithread();pthread->createthread();

用戶界面線程的執行次序與應用程序主線程相同,首先調用用戶界面線程類的initinstance()函數,如果返回true,繼續調用線程的run()函數,該函數的作用是運行一個標準的消息循環,并且當收到wm_quit消息后中斷,在消息循環過程中,run()函數檢測到線程空閑時(沒有消息),也將調用onidle()函數,最后run()函數返回,mfc調用exitinstance()函數清理資源。

你可以創建一個沒有界面而有消息循環的線程,例如:你可以從cwinthread派生一個新類,在initinstance函數中完成某項任務并返回false,這表示僅執行initinstance函數中的任務而不執行消息循環,你可以通過這種方法,完成一個工作者線程的功能。

三、線程間通訊

3.1通訊方式

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

3.1.1使用全局變量進行通信

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

3.1.2使用自定義消息

可以在一個線程的執行函數中向另一個線程發送自定義的消息來達到通信的目的。一個線程向另外一個線程發送消息是通過操作系統實現的。利用windows操作系統的消息驅動機制,當一個線程發出一條消息時,操作系統首先接收到該消息,然后把該消息轉發給目標線程,接收消息的線程必須已經建立了消息循環。

3.2例程

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

例程7[multithread7] 該例程演示了如何使用自定義消息進行線程間通信。首先,主線程向ccalculatethread線程發送消息wm_calculate,ccalculatethread線程收到消息后進行計算,再向主線程發送wm_display消息,主線程收到該消息后顯示計算結果。步驟:

四、線程的同步

4.1基本概念

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

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

臨界區(ccriticalsection)

事件(cevent)

互斥量(cmutex)

信號量(csemaphore)

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

4.2使用 ccriticalsection 類

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

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

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

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

4.訪問臨界區完畢后,使用ccriticalsection的成員函數unlock()來釋放臨界區:();通俗講,();語句時,如果其它線程(b)();();語句前的語句時,線程a就會等待,直到線程b執行完();語句,線程a才會繼續執行。

例程8 multithread8 4.3使用 cevent 類

cevent 類提供了對事件的支持。事件是一個允許一個線程在某種情況發生時,喚醒另外一個線程的同步對象。例如在某些網絡應用程序中,一個線程(記為a)負責監聽通訊端口,另外一個線程(記為b)負責更新用戶數據。通過使用cevent 類,線程a可以通知線程b何時更新用戶數據。每一個cevent 對象可以有兩種狀態:有信號狀態和無信號狀態。線程監視位于其中的cevent 類對象的狀態,并在相應的時候采取相應的操作。

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

1、cevent(bool binitiallyown=false,bool bmanualreset=false,lpctstr lpszname=null,lpsecurity_attributes lpsaattribute=null);binitiallyown:指定事件對象初始化狀態,true為有信號,false為無信號;

bmanualreset:指定要創建的事件是屬于人工事件還是自動事件。true為人工事件,false為自動事件;

后兩個參數一般設為null,在此不作過多說明。

2、bool cevent::setevent();

將 cevent 類對象的狀態設置為有信號狀態。如果事件是人工事件,則 cevent 類對象保持為有信號狀態,直到調用成員函數resetevent()將 其重新設為無信號狀態時為止。如果cevent 類對象為自動事件,則在setevent()將事件設置為有信號狀態后,cevent 類對象由系統自動重置為無信號狀態。

如果該函數執行成功,則返回非零值,否則返回零。

3、bool cevent::resetevent();

該函數將事件的狀態設置為無信號狀態,并保持該狀態直至setevent()被調用時為止。由于自動事件是由系統自動重置,故自動事件不需要調用該函數。如果該函數執行成功,返回非零值,否則返回零。一般通過調用waitforsingleobject函數來監視事件狀態。前面已經介紹了該函數。由于語言描述的原因,cevent 類的理解確實有些難度,只要通過下面例程,多看幾遍就可理解。例程9 multithread9 仔細分析這兩個線程函數, 就會正確理解cevent 類。線程writed執行到 waitforsingleobject(eventwrited.m_hobject,infinite);處等待,直到事件eventwrited為有信號該線程才往下執行,因為eventwrited對象是自動事件,則當waitforsingleobject()返回時,系統自動把eventwrited對象重置為無信號狀態。

4.4使用cmutex 類

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

4.5使用csemaphore 類

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

csemaphore 類的構造函數原型及參數說明如下:

csemaphore(long linitialcount=1,long lmaxcount=1,lpctstr pstrname=null,lpsecurity_attributes lpsaattributes=null);linitialcount:信號量對象的初始計數值,即可訪問線程數目的初始值;

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

后兩個參數在同一進程中使用一般為null,不作過多討論;

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

在信號量對象有信號的狀態下,線程執行到waitforsingleobject語句處繼續執行,同時可用線程數減1;若線程執行到waitforsingleobject語句時信號量對象無信號,線程就在這里等待,直到信號量對象有信號線程才往下執行。

Java 多線程編程篇二

in the following code, which is the earliest statement, where the object originally held in e, may be garbage collected:

class test {

static void main(string args []){

ee e = new employee(“bob”, 48);

atepay();

n(etails());

6.e = null;

7.e = new employee(“denise”, 36);

atepay();

n(etails());

10.}

11.}

only one:

in the following code, which is the earliest statement, where the object originally held in e, may be garbage collected:

class test {

static void main(string args []){

ee e = new employee(“bob”, 48);

atepay();

n(etails());

6.e = null;

7.e = new employee(“denise”, 36);

atepay();

n(etails());

10.}

11.}

only one:

10

11

7

8

2:exhibit :

class test(e static int j = 0;

e static boolean methodb(int k)(5.j += k;

true;

6.)

static void methoda(int i){

n b:

10.b = i < 10 | methodb(4);

11.b = i < 10 || methodb(8);

12.)

static void main(string args[] }(a(0);

n(j);

17.)

18.)

what is the result?

program prints “0”

program prints “4”

program prints “8”

program prints “12”

3:what is written to the standard output given the following statement:n(4|7);

select the right answer:

a.4

b.5

c.6

d.7

4:

select valid identifier of java:

select valid identifier of java:

a.%passwd

b.3d_game

c.$charge

5:設有變量說明語句int a=1,b=0;

則執行以下程序段的輸出結果為()。

switch(a)

{

case 1:

switch(b)

{

case 0:printf(“**0**”);break;

case 1:printf(“**1**”);break;

}

case 2:printf(“**2**”);break;

}

printf(“ ”);

a.**0**

b.**0****2**

c.**0****1****2**

d.有語法錯誤

6:in the following pieces of code, which one will compile without any error?

buffer sb1 = “abcd”;

n b = new boolean(“abcd”);

c.c: byte b = 255;

fl = 1.2;

7:

what is the result when you compile and run the following code?

public class throwsdemo

{

static void throwmethod()

{

n(“inside throwmethod.”);

throw new illegalaccessexception(“demo”);

}

public static void main(string args[])

{

try

{

throwmethod();

}

catch(illegalaccessexception e)

{

n(“caught ” + e);

}

}

}

choices:

what is the result when you compile and run the following code?

public class throwsdemo

{

static void throwmethod()

{

n(“inside throwmethod.”);

throw new illegalaccessexception(“demo”);

}

public static void main(string args[])

{

try

{

throwmethod();

}

catch(illegalaccessexception e)

{

n(“caught ” + e);

}

}

}

choices:

ation error

e error

e successfully, nothing is ed by caught:laccessexcption: demo

8:which of the following statements are not legal?

l = 4990;

i = 4l;

d = 34.4;

t = 0.9f.9:

give the following java class:

public class example{

public static void main(string args[]){

static int x[] = new int[15];

n(x[5]);

}

}

which statement is corrected?

give the following java class:

public class example{

public static void main(string args[]){

static int x[] = new int[15];

n(x[5]);

}

}

which statement is corrected?

compile, some error will run, some error will is is null.10:下面關于變量及其范圍的陳述哪些是錯的。

a.實例變量是類的成員變量。

b.實例變量用關鍵字static聲明。

c.在方法中定義的局部變量在該方法被執行時創建

d.局部變量在使用前必須被初始化。

11:

public class x{

public object m(){

object o = new float(3.14f);//line 3

object [] oa = new object[1];//line 4

oa[0] = o;//line 5

o=null;//line 6

return oa[0];//line 7

}

}

when is the float object, created in line 3,eligible for garbage collection?

public class x{

public object m(){

object o = new float(3.14f);//line 3

object [] oa = new object[1];//line 4

oa[0] = o;//line 5

o=null;//line 6

return oa[0];//line 7

}

}

when is the float object, created in line 3,eligible for garbage collection?

after line after line 6

after line 7(that is,as the method returns)

in this method

12:

which is the most appropriate code snippet that can be inserted at line 18 in the following code?

(assume that the code is compiled and run with assertions enabled)

.*;

class asserttest

4.{

e hashmap cctld;

asserttest()

8.{

= new hashmap();

(“in”, “india”);

(“uk”, “united kingdom”);

(“au”, “australia”);

13.// more code...14.}

15.// other methods.... string getcountry(string countrycode)

17.{

18.// what should be inserted here?

country =(string)(countrycode);

country;

21.}

22.}

which is the most appropriate code snippet that can be inserted at line 18 in the following code?

(assume that the code is compiled and run with assertions enabled)

.*;

class asserttest

4.{

e hashmap cctld;

asserttest()

8.{

= new hashmap();

(“in”, “india”);

(“uk”, “united kingdom”);

(“au”, “australia”);

13.// more code...14.}

15.// other methods.... string getcountry(string countrycode)

17.{

18.// what should be inserted here?

country =(string)(countrycode);

country;

21.}

22.}

countrycode!= null;

countrycode!= null : “country code can not be null”;

cctld!= null : “no country code data is available”;

cctld : “no country code data is available”;

13:

give the following code:

public class example{

public static void main(string args[]){

int l=0;

do{

n(“doing it for l is:”+l);

}while(—l>0)

n(“finish”);

}

}

which well be output:

give the following code:

public class example{

public static void main(string args[]){

int l=0;

do{

n(“doing it for l is:”+l);

}while(—l>0)

n(“finish”);

}

}

which well be output:

it for l is 3

it for l is 1

it for l is 2

it for l is 0

14:which statements about java code security are not true?

bytecode verifier loads all classes needed for the execution of a ing code is performed by the runtime runtime the bytecodes are loaded, checked and run in an interpreter. class loader adds security by separating the namespaces for the classes of the local file system from those imported from network sources.15:a class design requires that a member variable should be accessible only by same package, which modifer word should be used?

ted

modifer

e

16:character流與byte流的區別是

a.每次讀入的字節數不同

b.前者帶有緩沖,后者沒有

c.前者是塊讀寫,后者是字節讀寫

d.二者沒有區別,可以互換使用

簡答題

17:找出兩個字符串中最大子字符串,如“abractyeyt”,“dgdsaeactyey”的最大子串為“actyet”

18:假設你有一個用1001個整數組成的數組,這些整數是任意排列的,但是你知道所有的整數都在1到1000(包括1000)之間。此外,除一個數字出現兩次外,其他所有數字只出現一次。假設你只能對這個數組做一次處理,用一種算法找出重復的那個數字。如果你在運算中使用了輔助的存儲方式,那么你能找到不用這種方式的算法嗎?

19:到底在哪里使用cascade=“...”?

20:使用tomcat部署應用程序 emoryerror 嗎?如何解決的。

21:請寫一個java程序實現數據庫緩沖池的功能?

22:有200個正整數,且每個數均在1000至9999之間。請編制函數,其函數的功能是:要求按每個數的后三位的大小進行升序排列,然后取出滿足此條件的前10個數依次存入數組bb中,如果后三位的數值相等,則按原先的數值進行降序排列。

23:anonymous inner class(匿名內部類)是否可以extends(繼承)其它類,是否可以implements(實現)interface(接口)?

24:找出字符串a中包含的字符可以進行的所有不同組合。例如:abccd中,ab,ac,bc,cc,abd等都是可能的組合。

25:下面的代碼在絕大部分時間內都運行得很正常,請問在什么情況下會出現問題?問題的根源在哪里?

import .linkedlist;

public class stack {

linkedlist list = new linkedlist();

public synchronized void push(object x){

synchronized(list){

t(x);

notify();

}

}

public synchronized object pop()

throws exception {

synchronized(list){

if(()<= 0){

wait();

}

return last();

}

}

}

Java 多線程編程篇三

《java編程》

計算器

班級:****** 姓名:******

學號: ******* 指導老師:******

實驗名稱:java計算器

1實驗目的: java編程語言在編程方面的具體應用,以及使用面向對象方法,對小應用程序進行需求分

析、概要設計、詳細設計,最后使用java編程實現的全過程。

2實驗意義:

在編程我們使用的java語言,是目前比較流行的編程語言。在當今這個時代,java語言在編程方面的優勢使得編程有了更好的選擇。java語言最大的特點是具有跨平臺性,使其不受平臺不同的影響,得到了廣泛的應用。實訓性質

本課程是計算機信息管理專業的一門實踐性課程,是《java編程》課程的實踐性教學環節。實訓目標

⑴綜合應用java程序設計的知識解決實際問題。

⑵學會在應用程序的設計過程中,應用面向對象的程序設計方法。⑶學會應用jdbc創建數據庫應用程序。

⑷學會開發基于swing的應用程序及多文檔應用程序的設計。實訓任務

用java語言開發工具(例如jdk、jcreator、netbeans等)制作一個簡單的可運行的完整的應用程序或小型系統,并編制出各階段必要的文檔。

將創建一個計算器,可以進行常用的加減乘除算術運算。本實例的知識點有:窗口布局器gridlayout的應用,對按鈕消息的監聽和響應。

6實訓條件

<軟件:>windows xp,netbeans ide 6.52 7開發背景: java是由sun microsystems公司于1995年5月推出的java程序設計語言(以下簡稱java語言)和java平臺的總稱。java語言是一個支持網絡計算的面向對象程序設計語言。java語言吸收了smalltalk語言和c++語言的優點,并增加了其它特性,如支持并發程序設計、網絡通信、和多媒體數據控制等。

8系統部分分析:

1)java語言是簡單的。java語言的語法與c語言和c++語言很接近,使得大多數程序員很容易學習和使用java。另一方面,java丟棄了c++ 中很少使用的、很難理解的、令人迷惑的那些特性,如操作符重載、多繼承、自動的強制類型轉換。

2)java語言是一個面向對象的。java語言提供類、接口和繼承等原語,為了簡單起見,只支持類之間的單繼承,但支持接口之間的多繼承,并支持類與接口之間的實現機制(關鍵字為implements)。java語言全面支持動態綁定,而c++ 語言只對虛函數使用動態綁定

3)java語言是分布式的。java語言支持internet應用的開發,在基本的java應用編程接口中有一個網絡應用編程接口(),它提供了用于網絡應用編程的類庫,包括url、urlconnection、socket、serversocket等。java的rmi(遠程方法激活)機制也是開發分布式應用的重要手段。

4)java語言是健壯的。java的強類型機制、異常處理、廢料的自動收集等是java程序健壯性的重要保證。對指針的丟棄是java的明智選擇。java的安全檢查機制使得java更具健壯性。

5)java語言是安全的。java通常被用在網絡環境中,為此,java提供了一個安全機制以防惡意代碼的攻擊。除了java語言具有的許多安全特性以外,java對通過網絡下載的類具有一個安全防范機制(類classloader),如分配不同的名字空間以防替代本地的同名類、字節代碼檢查,并提供安全管理機制.6)java語言是體系結構中立的。java程序(后綴為java的文件)在java平臺上被編譯為體系結構中立的字節碼格式(后綴為class的文件), 然后可以在實現這個java平臺的任何系統中運行。

7)java語言是可移植的。這種可移植性來源于體系結構中立性,另外,java還嚴格規定了各個基本數據類型的長度。java系統本身也具有很強的可移植性,java編譯器是用java實現的.8)java語言是解釋型的。如前所述,java程序在java平臺上被編譯為字節碼格式,然后可以在實現這個java平臺的任何系統中運行。

9)java是高性能的。與那些解釋型的高級腳本語言相比,java的確是高性能的。事實上,java的運行速度隨著jit(just-in-time)編譯器技術的發展越來越接近于c++。

10)java語言是多線程的。在java語言中,線程是一種特殊的對象,它必須由thread類或其子(孫)類來創建。

11)java語言是動態的。java語言的設計目標之一是適應于動態變化的環境。

目錄

課程設計題目 ……………………………… p1

課程設計簡介 ……………………………… p2

課程設計源代碼…………………………… p5

課程設計運行結果 ……………………… p15 課程設計心得體會 ………………………

p16

package computerpad;import .*;import .event.*;import .*;import .*;import list;import format;public class computerpad extends frame implements actionlistener {

numberbutton numberbutton[];

operationbutton oprationbutton[];

button 小數點按鈕,正負號按鈕,退格按鈕,求倒數按鈕,等號按鈕,清零按鈕;

panel panel;

jtextfield resultshow;

string 運算符號[]={“+”,“-”,“*”,“/”};

linkedlist 鏈表;

boolean 是否按下等號=false;

public computerpad()

{

super(“計算器”);

鏈表=new linkedlist();

numberbutton=new numberbutton[10];

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

{

numberbutton[i]=new numberbutton(i);

numberbutton[i].addactionlistener(this);

}

oprationbutton=new operationbutton[4];

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

{

oprationbutton[i]=new operationbutton(運算符號[i]);

oprationbutton[i].addactionlistener(this);

}

小數點按鈕=new button(“.”);

正負號按鈕

=new button(“+/-”);

等號按鈕=new button(“=”);

求倒數按鈕=new button(“1/x”);

退格按鈕=new button(“退格”);

清零按鈕=new button(“c”);

eground();

eground();

eground();

eground();

eground();

eground();

ionlistener(this);

ionlistener(this);

ionlistener(this);

ionlistener(this);

ionlistener(this);

ionlistener(this);

resultshow=new jtextfield(10);

izontalalignment();

eground();

t(new font(“timesroman”,,14));

der(new softbevelborder(d));

kground();

table(false);

panel=new panel();

out(new gridlayout(4,5));

(numberbutton[1]);

(numberbutton[2]);

(numberbutton[3]);

(oprationbutton[0]);

(清零按鈕);

(numberbutton[4]);

(numberbutton[5]);

(numberbutton[6]);

(oprationbutton[1]);

(退格按鈕);

(numberbutton[7]);

(numberbutton[8]);

(numberbutton[9]);

(oprationbutton[2]);

(求倒數按鈕);

(numberbutton[0]);

(正負號按鈕);

(小數點按鈕);

(oprationbutton[3]);

(等號按鈕);

add(panel,);

add(resultshow,);

addwindowlistener(new windowadapter()

{ public void windowclosing(windowevent e)

{

(0);

}

});

setvisible(true);

setbounds(100,50,240,180);

setresizable(false);

validate();

} public void actionperformed(actionevent e)

{

if(rce()instanceof numberbutton)

{

numberbutton b=(numberbutton)rce();

if(()==0)

{

int number=ber();

(“"+number);

t(”“+number);

是否按下等號=false;

}

else if(()==1&&是否按下等號==false)

{

int number=ber();

string num=(string)first();

string s=(”“+number);

(0,s);

t(s);

}

else if(()==1&&是否按下等號==true)

{

int number=ber();

first();

(”“+number);

是否按下等號=false;

t(”“+number);

}

else if(()==2)

{

int number=ber();

(”“+number);

t(”“+number);

}

else if(()==3)

{

int number=ber();

string num=(string)t();

string s=(”“+number);

(2,s);

t(s);

}

}

else if(rce()instanceof operationbutton)

{

operationbutton b=(operationbutton)rce();

if(()==1)

{

string fuhao=運算符號();

(fuhao);

}

else if(()==2)

{

string fuhao=運算符號();

(1,fuhao);

}

else if(()==3)

{

string fuhao=運算符號();

string number1=(string)first();

string number2=(string)t();

string 運算符號=(string)(1);

try

{

double n1=ouble(number1);

double n2=ouble(number2);

double n=0;

if((”+“))

{

n=n1+n2;

}

else if((”-“))

{

n=n1-n2;

}

else if((”*“))

{

n=n1*n2;

}

else if((”/“))

{

n=n1/n2;

}

();

(”“+n);

(fuhao);

t(”“+n);

}

catch(exception ee)

{

}

}

}

else if(rce()==等號按鈕)

{

是否按下等號=true;

if(()==1||()==2)

{

string num=(string)first();

t(”“+num);

}

else if(()==3)

{

string number1=(string)first();

string number2=(string)t();

string 運算符號=(string)(1);

try

{

double n1=ouble(number1);

double n2=ouble(number2);

double n=0;

if((”+“))

{

n=n1+n2;

}

else if((”-“))

{

n=n1-n2;

}

else if((”*“))

{

n=n1*n2;

}

else if((”/“))

{

n=n1/n2;

}

t(”“+n);

(0,”“+n);

last();

last();

}

catch(exception ee)

{

}

}

}

else if(rce()==小數點按鈕)

{

if(()==0)

{

是否按下等號=false;

}

else if(()==1)

{

string dot=el();

string num=(string)first();

string s=null;

if(f(dot)==-1)

{

s=(dot);

(0,s);

}

else

{

s=num;

}

(0,s);

t(s);

}

else if(()==3)

{

string dot=el();

string num=(string)t();

string s=null;

if(f(dot)==-1)

{

s=(dot);

(2,s);

}

else

{

s=num;

}

t(s);

}

}

else if(rce()==退格按鈕)

{

if(()==1)

{

string num=(string)first();

if(()>=1)

{

num=ing(0,()-1);

(0,num);

t(num);

}

else

{

last();

t(”0“);

}

}

else if(()==3)

{

string num=(string)t();

if(()>=1)

{ num=ing(0,()-1);

(2,num);

t(num);

}

else

{

last();

t(”0“);

}

}

}

else if(rce()==正負號按鈕)

{

if(()==1)

{

string number1=(string)first();

try

{

double d=ouble(number1);

d=-1*d;

string str=f(d);

(0,str);

t(str);

}

catch(exception ee)

{

}

}

else if(()==3)

{

string number2=(string)t();

try

{

double d=ouble(number2);

d=-1*d;

string str=f(d);

(2,str);

t(str);

}

catch(exception ee){

}

}

}

else if(rce()==求倒數按鈕)

{

if(()==1||()==2)

{

string number1=(string)first();

try

{

double d=ouble(number1);

d=1.0/d;

string str=f(d);

(0,str);

t(str);

}

catch(exception ee){

}

}

else if(()==3)

{

string number2=(string)t();

try

{

double d=ouble(number2);

d=1.0/d;

string str=f(d);

(0,str);

t(str);

}

catch(exception ee){

}

}

}

else if(rce()==清零按鈕)

{

是否按下等號=false;

t(”0“);

();

}

} public static void main(string args[])

{

new computerpad();

}

}

package computerpad;import .*;import .event.*;import .*;public class numberbutton extends button {

int number;

public numberbutton(int number)

{

super(”"+number);

=number;

setforeground();

}

public int getnumber()

{

return number;

} }

import .*;import .event.*;import .*;public class operationbutton extends button {

string 運算符號;

public operationbutton(string s)

{

super(s);

運算符號=s;

setforeground();

}

public string get運算符號()

{

return 運算符號;

} } 14 java實訓心得:

未接觸java之前,聽人說java這門語言如何的強大和難以入門,但學習之后,給我的感覺卻是語言沒有所謂的難于不難,關鍵是自己有沒有真正投入去學,有沒有花時間去學。java是一門很好的語言,經過周圍人對java的宣傳,我一開始不敢去學習這門語言,因為一門高級語言總是讓人想到一開始的學習會很難,但是后來在自己的努力和老師同學的幫助下,我加入了java學習者的行列。

老師把我們帶進了門,那么,以后漫長的深入學習還是要靠自己。經常性的編寫一些程序,或則去看懂、研究透別人編寫的程序對于我們打好基礎是非常有利的。讓我們懷著對java的一腔熱情,用自己的刻苦努力去把java學好。將來,用自己的成績去回報有恩于我們的社會、家人和朋友。

Java 多線程編程篇四

c++多線程編程簡單實例(2012-05-18 16:26:01)

轉載▼

標簽:

it

c++本身并沒有提供任何多線程機制,但是在windows下,我們可以調用sdk win32 api來編寫多線程的程序,下面就此簡單的講一下:

創建線程的函數

handle createthread(lpsecurity_attributes lpthreadattributes, // sd

size_t dwstacksize,// initial stack size

lpthread_start_routine lpstartaddress,// thread function

lpvoid lpparameter,// thread argument

dword dwcreationflags,// creation option

lpdword lpthreadid// thread identifier);

在這里我們只用到了第三個和第四個參數,第三個參數傳遞了一個函數的地址,也是我們要指定的新的線程,第四個參數是傳給新線程的參數指針。

eg1:

#include

#include

using namespace std;

dword winapi fun(lpvoid lpparamter)

{

while(1){ cout<<“fun display!”<

}

int main()

{

handle hthread = createthread(null, 0, fun, null, 0, null);

closehandle(hthread);

while(1){ cout<<“main display!”<

return 0;

}

我們可以看到主線程(main函數)和我們自己的線程(fun函數)是隨機地交替執行的,但是兩個線程輸出太快,使我們很難看清楚,我們可以使用函數

void sleep(dword dwmilliseconds// sleep time);

來暫停線程的執行,dwmilliseconds表示千分之一秒,所以

sleep(1000);

表示暫停1秒

eg2:

#include

#include

using namespace std;

dword winapi fun(lpvoid lpparamter)

{

while(1){ cout<<“fun display!”<

}

int main()

{

handle hthread = createthread(null, 0, fun, null, 0, null);

closehandle(hthread);

while(1){ cout<<“main display!”<

return 0;

}

執行上述代碼,這次我們可以清楚地看到在屏幕上交錯地輸出fun display!和main display!,我們發現這兩個函數確實是并發運行的,細心的讀者可能會發現我們的程序是每當fun函數和main函數輸出內容后就會輸出換行,但是我們看到的確是有的時候程序輸出換行了,有的時候確沒有輸出換行,甚至有的時候是輸出兩個換行。這是怎么回事?下面我們把程序改一下看看:

eg3:

#include

#include

using namespace std;

dword winapi fun(lpvoid lpparamter)

{

while(1){ cout<<“fun display!n”;sleep(1000);}

}

int main()

{

handle hthread = createthread(null, 0, fun, null, 0, null);

closehandle(hthread);

while(1){ cout<<“main display!n”;sleep(2000);}

return 0;

}

我們再次運行這個程序,我們發現這時候正如我們預期的,正確地輸出了我們想要輸出的內容并且格式也是正確的。下面我就來講一下此前我們的程序為什么沒有正確的運行。多線程的程序時并發地運行的,多個線程之間如果公用了一些資源的話,我們并不能保證這些資源都能正確地被利用,因為這個時候資源并不是獨占的,舉個例子吧:

eg4:

加入有一個資源 int a = 3

有一個線程函數 selfadd()該函數是使 a += a;

又有一個線程函數 selfsub()該函數是使a-= a;

我們假設上面兩個線程正在并發欲行,如果selfadd在執行的時候,我們的目的是想讓a編程6,但此時selfsub得到了運行的機會,所以a變成了0,等到selfadd的到執行的機會后,a += a,但是此時a確是0,并沒有如我們所預期的那樣的到6,我們回到前面eg2,在這里,我們可以把屏幕看成是一個資源,這個資源被兩個線程所共用,加入當fun函數輸出了fun display!后,將要輸出endl(也就是清空緩沖區并換行,在這里我們可以不用理

解什么事緩沖區),但此時main函數確得到了運行的機會,此時fun函數還沒有來得及輸出換行就把cpu讓給了main函數,而這時main函數就直接在fun display!后輸出main display!,至于為什么有的時候程序會連續輸出兩個換行,讀者可以采用同樣的分析方法來分析,在這里我就不多講了,留給讀者自己思考了。

那么為什么我們把eg2改成eg3就可以正確的運行呢?原因在于,多個線程雖然是并發運行的,但是有一些操作是必須一氣呵成的,不允許打斷的,所以我們看到eg2和eg3的運行結果是不一樣的。

那么,是不是eg2的代碼我們就不可以讓它正確的運行呢?答案當然是否,下面我就來講一下怎樣才能讓eg2的代碼可以正確運行。這涉及到多線程的同步問題。對于一個資源被多個線程共用會導致程序的混亂,我們的解決方法是只允許一個線程擁有對共享資源的獨占,這樣就能夠解決上面的問題了。

handle createmutex(lpsecurity_attributes lpmutexattributes,// sd

bool binitialowner,// initial owner

lpctstr lpname// object name);

該函數用于創造一個獨占資源,第一個參數我們沒有使用,可以設為null,第二個參數指定該資源初始是否歸屬創建它的進程,第三個參數指定資源的名稱。

handle hmutex = createmutex(null,true,“screen”);

這條語句創造了一個名為screen并且歸屬于創建它的進程的資源

bool releasemutex(handle hmutex// handle to mutex);

該函數用于釋放一個獨占資源,進程一旦釋放該資源,該資源就不再屬于它了,如果還要用到,需要重新申請得到該資源。申請資源的函數如下

dword waitforsingleobject(handle hhandle,// handle to object

dword dwmilliseconds// time-out interval);

第一個參數指定所申請的資源的句柄,第二個參數一般指定為infinite,表示如果沒有申請到資源就一直等待該資源,如果指定為0,表示一旦得不到資源就返回,也可以具體地指定等待多久才返回,單位是千分之一秒。好了,該到我們來解決eg2的問題的時候了,我們可以把eg2做一些修改,如下

eg5:

#include

#include

using namespace std;

handle hmutex;

dword winapi fun(lpvoid lpparamter)

{

while(1){

waitforsingleobject(hmutex, infinite);

cout<<“fun display!”<

sleep(1000);

releasemutex(hmutex);

}

}

int main()

{

handle hthread = createthread(null, 0, fun, null, 0, null);hmutex = createmutex(null, false, “screen”);

closehandle(hthread);

while(1){

waitforsingleobject(hmutex, infinite);

cout<<“main display!”<

sleep(2000);

releasemutex(hmutex);

}

return 0;

}

運行代碼正如我們所預期的輸出的內容。

Java 多線程編程篇五

java多線程編程總結

2007-05-17 11:21:59 標簽:java 多線程

原創作品,允許轉載,轉載時請務必以超鏈接形式標明文章 原始出處、作者信息和本聲明。否則將追究法律責任。http:///62575/27069

java多線程編程總結

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

java線程:概念與原理 java線程:創建與啟動

java線程:線程棧模型與線程的變量 java線程:線程狀態的轉換 java線程:線程的同步與鎖 java線程:線程的交互 java線程:線程的調度-休眠 java線程:線程的調度-優先級 java線程:線程的調度-讓步 java線程:線程的調度-合并 java線程:線程的調度-守護線程 java線程:線程的同步-同步方法 java線程:線程的同步-同步塊

java線程:并發協作-生產者消費者模型 java線程:并發協作-死鎖 java線程:volatile關鍵字 java線程:新特征-線程池

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

----

下面的內容是很早之前寫的,內容不夠充實,而且是基于java1.4的內容,java5之后,線程并發部分擴展了相當多的內容,因此建議大家看上面的系列文章的內容,與時俱進,跟上java發展的步伐。----

一、認識多任務、多進程、單線程、多線程 要認識多線程就要從操作系統的原理說起。

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

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

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

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

java編寫程序都運行在在java虛擬機(jvm)中,在jvm的內部,程序的多任務是通過線程來實現的。每用java命令啟動一個java應用程序,就會啟動一個jvm進程。在同一個jvm進程中,有且只有一個進程,就是它自己。在這個jvm環境中,所有程序代碼的運行都是以線程來運行。

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

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

實際上,操作的系統的多進程實現了多任務并發執行,程序的多線程實現了進程的并發執行。多任務、多進程、多線程的前提都是要求操作系統提供多任務、多進程、多線程的支持。

在java程序中,jvm負責線程的調度。線程調度是值按照特定的機制為多個線程分配cpu的使用權。調度的模式有兩種:分時調度和搶占式調度。分時調度是所有線程輪流獲得cpu使用權,并平均分配每個線程占用cpu的時間;搶占式調度是根據線程的優先級別來獲取cpu的使用權。jvm的線程調度模式采用了搶占式模式。

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

用一句話做總結:雖然操作系統是多線程的,但cpu每一時刻只能做一件事,和人的大腦是一樣的,呵呵。

二、java與多線程

java語言的多線程需要操作系統的支持。

java 虛擬機允許應用程序并發地運行多個執行線程。java語言提供了多線程編程的擴展點,并給出了功能強大的線程控制api。

在java中,多線程的實現有兩種方式: 類 le接口

每個線程都有一個優先級,高優先級線程的執行優先于低優先級線程。每個線程都可以或不可以標記為一個守護程序。當某個線程中運行的代碼創建一個新 thread 對象時,該新線程的初始優先級被設定為創建線程的優先級,并且當且僅當創建線程是守護線程時,新線程才是守護程序。

當 java 虛擬機啟動時,通常都會有單個非守護線程(它通常會調用某個指定類的 main 方法)。java 虛擬機會繼續執行線程,直到下列任一情況出現時為止:

調用了 runtime 類的 exit 方法,并且安全管理器允許退出操作發生。

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

三、類

/** * file name: * created by: intellij idea.* copyright: copyright(c)2003-2006 * company: lavasoft([url]http:///[/url])* author: leizhimin * modifier: leizhimin * date time: 2007-5-17 10:03:12 * readme: 通過擴展thread類實現多線程 */ public class testmitithread { public static void main(string[] rags){ n(tthread().getname()+ “ 線程運行開始!”);new mitisay(“a”).start();new mitisay(“b”).start();n(tthread().getname()+ “ 線程運行結束!”);} }

class mitisay extends thread { public mitisay(string threadname){ super(threadname);}

public void run(){ n(getname()+ “ 線程運行開始!”);for(int i = 0;i < 10;i++){ n(i + “ ” + getname());try { sleep((int)()* 10);} catch(interruptedexception e){ tacktrace();} } n(getname()+ “ 線程運行結束!”);} }

運行結果:

main 線程運行開始!main 線程運行結束!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 線程運行結束!2 b 3 b 4 b 5 b 6 b 7 b 8 b 9 b b 線程運行結束!說明:

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

在一個方法中調用tthread().getname()方法,可以獲取當前線程的名字。在mian方法中調用該方法,獲取的是主線程的名字。

注意:start()方法的調用后并不是立即執行多線程代碼,而是使得該線程變為可運行態(runnable),什么時候運行是由操作系統決定的。

從程序運行的結果可以發現,多線程程序是亂序執行。因此,只有亂序執行的代碼才有必要設計為多線程。

()方法調用目的是不讓當前線程獨自霸占該進程所獲取的cpu資源,以留出一定時間給其他線程執行的機會。

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

四、le接口

/** * 通過實現 runnable 接口實現多線程 */ public class testmitithread1 implements runnable {

public static void main(string[] args){ n(tthread().getname()+ “ 線程運行開始!”);testmitithread1 test = new testmitithread1();thread thread1 = new thread(test);thread thread2 = new thread(test);();();n(tthread().getname()+ “ 線程運行結束!”);}

public void run(){ n(tthread().getname()+ “ 線程運行開始!”);for(int i = 0;i < 10;i++){ n(i + “ ” + tthread().getname());try { ((int)()* 10);} catch(interruptedexception e){ tacktrace();} } n(tthread().getname()+ “ 線程運行結束!”);} }

運行結果:

main 線程運行開始!thread-0 線程運行開始!main 線程運行結束!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 線程運行結束!8 thread-1 9 thread-1 thread-1 線程運行結束!說明:

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

在啟動的多線程的時候,需要先通過thread類的構造方法thread(runnable target)構造出對象,然后調用thread對象的start()方法來運行多線程代碼。

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

五、讀解thread類api

static int max_priority 線程可以具有的最高優先級。static int min_priority 線程可以具有的最低優先級。static int norm_priority 分配給線程的默認優先級。

構造方法摘要

thread(runnable target)分配新的 thread 對象。thread(string name)分配新的 thread 對象。

方法摘要

static thread currentthread()返回對當前正在執行的線程對象的引用。classloader getcontextclassloader()返回該線程的上下文 classloader。long getid()返回該線程的標識符。string getname()返回該線程的名稱。int getpriority()返回線程的優先級。 getstate()返回該線程的狀態。threadgroup getthreadgroup()返回該線程所屬的線程組。static boolean holdslock(object obj)當且僅當當前線程在指定的對象上保持監視器鎖時,才返回 true。void interrupt()中斷線程。

static boolean interrupted()測試當前線程是否已經中斷。boolean isalive()測試線程是否處于活動狀態。boolean isdaemon()測試該線程是否為守護線程。boolean isinterrupted()測試線程是否已經中斷。void join()等待該線程終止。void join(long millis)等待該線程終止的時間最長為 millis 毫秒。void join(long millis, int nanos)等待該線程終止的時間最長為 millis 毫秒 + nanos 納秒。void resume()已過時。該方法只與 suspend()一起使用,但 suspend()已經遭到反對,因為它具有死鎖傾向。有關更多信息,請參閱為何 、d 和 遭到反對?。void run()如果該線程是使用獨立的 runnable 運行對象構造的,則調用該 runnable 對象的 run 方法;否則,該方法不執行任何操作并返回。void setcontextclassloader(classloader cl)設置該線程的上下文 classloader。void setdaemon(boolean on)將該線程標記為守護線程或用戶線程。

static void setdefaultuncaughtexceptionhandler(htexceptionhandler eh)設置當線程由于未捕獲到異常而突然終止,并且沒有為該線程定義其他處理程序時所調用的默認處理程序。void setname(string name)改變線程名稱,使之與參數 name 相同。void setpriority(int newpriority)更改線程的優先級。

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

六、線程的狀態轉換圖

線程在一定條件下,狀態會發生變化。線程變化的狀態轉換圖如下:

1、新建狀態(new):新創建了一個線程對象。

2、就緒狀態(runnable):線程對象創建后,其他線程調用了該對象的start()方法。該狀態的線程位于可運行線程池中,變得可運行,等待獲取cpu的使用權。

3、運行狀態(running):就緒狀態的線程獲取了cpu,執行程序代碼。

4、阻塞狀態(blocked):阻塞狀態是線程因為某種原因放棄cpu使用權,暫時停止運行。直到線程進入就緒狀態,才有機會轉到運行狀態。阻塞的情況分三種:

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

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

(三)、其他阻塞:運行的線程執行sleep()或join()方法,或者發出了i/o請求時,jvm會把該線程置為阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者i/o處理完畢時,線程重新轉入就緒狀態。

5、死亡狀態(dead):線程執行完了或者因異常退出了run()方法,該線程結束生命周期。

七、線程的調度

1、調整線程優先級:java線程有優先級,優先級高的線程會獲得較多的運行機會。

java線程的優先級用整數表示,取值范圍是1~10,thread類有以下三個靜態常量: static int max_priority 線程可以具有的最高優先級,取值為10。static int min_priority 線程可以具有的最低優先級,取值為1。static int norm_priority 分配給線程的默認優先級,取值為5。

thread類的setpriority()和getpriority()方法分別用來設置和獲取線程的優先級。

每個線程都有默認的優先級。_priority。

線程的優先級有繼承關系,比如a線程中創建了b線程,那么b將和a具有相同的優先級。jvm提供了10個線程優先級,但與常見的操作系統都不能很好的映射。如果希望程序能移植到各個操作系統中,應該僅僅使用thread類有以下三個靜態常量作為優先級,這樣能保證同樣的優先級采用了同樣的調度方式。

2、線程睡眠:(long millis)方法,使線程轉到阻塞狀態。millis參數設定睡眠的時間,以毫秒為單位。當睡眠結束后,就轉為就緒(runnable)狀態。sleep()平臺移植性好。

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

4、線程讓步:()方法,暫停當前正在執行的線程對象,把執行機會讓給相同或者更高優先級的線程。

5、線程加入:join()方法,等待其他線程終止。在當前線程中調用另一個線程的join()方法,則當前線程轉入阻塞狀態,直到另一個進程運行結束,當前線程再由阻塞轉為就緒狀態。

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

7、常見線程名詞解釋

主線程:jvm調用程序mian()所產生的線程。

當前線程:這個是容易混淆的概念。tthread()來獲取的進程。后臺線程:指為其他線程提供服務的線程,也稱為守護線程。jvm的垃圾回收線程就是一個后臺線程。

前臺線程:是指接受后臺線程服務的線程,其實前臺后臺線程是聯系在一起,就像傀儡和幕后操縱者一樣的關系。傀儡是前臺線程、幕后操縱者是后臺線程。由前臺線程創建的線程默認也是前臺線程。可以通過isdaemon()和setdaemon()方法來判斷和設置一個線程是否為后臺線程。

本文出自 “熔 巖” 博客,請務必保留此出處http:///62575/27069

全文閱讀已結束,如果需要下載本文請點擊

下載此文檔
a.付費復制
付費獲得該文章復制權限
特價:5.99元 10元
微信掃碼支付
已付款請點這里
b.包月復制
付費后30天內不限量復制
特價:9.99元 10元
微信掃碼支付
已付款請點這里 聯系客服
主站蜘蛛池模板: 日韩女优在线观看 | 免费观看的av网站 | 伊伊人成亚洲综合人网香 | 免费视频网站在线观看入口 | 日本xxxx裸体xxxx出水 | 久久96国产精品久久 | 蜜桃av噜噜一区二区三区 | 成人午夜又粗又硬又大 | 男女做激情爱呻吟口述全过程 | 无码国产69精品久久久久网站 | 一级片在线播放 | 亚洲精品视频在线免费播放 | 四虎小视频 | 日韩国产成人无码av毛片 | 中午字幕在线观看 | 久久精品国产一区二区三区肥胖 | 91丨九色丨刺激 | 欧美性受xxxx黑人猛交88 | 唯美欧美亚洲 | 国内精品久久久久影视老司机 | 日本熟妇色一本在线看 | 色视频网 | 99国产欧美久久久精品 | 中文字幕在线观看一区二区三区 | 欧美激情图片 | 首页干日本少妇 | 女人精69xxx免费观 | 激情亚洲天堂 | 免费看污黄网站在线观看 | 国产女人的高潮国语对白 | 夜夜骚av| 国产亚洲精品久久久久久青梅 | 久久久精品网站 | 长篇乱肉合集乱500小说日本 | 丰满岳跪趴高撅肥臀尤物在线观看 | 国精品人妻无码一区二区三区蜜柚 | 国产精品成人免费精品自在线观看 | 一区二区三区不卡在线观看 | 色射影院| 亚洲国产精品一区二区久久 | 男女乱淫真视频免费播放 | 九月婷婷人人澡人人添人人爽 | 成人免费网站在线 | 美国一级大黄一片免费中文 | 国产第一亚洲 | 国产乱对白刺激在线视频 | 97色偷偷色噜噜狠狠爱网站 | 永久av网站 | 男人边吻奶边挵进去视频 | 久久久亚洲欧洲 | 国产av人人夜夜澡人人爽麻豆 | 一道本道加勒比天天看 | 男人和女人高潮做爰视频 | 久久婷婷精品一区二区三区日本 | 色视频一区二区三区 | 天堂8中文在线最新版在线 拍真实国产伦偷精品 | 久久爱影视i | 国产理论在线观看 | 九九re6热在线视频精品66 | 亚洲免费一级视频 | 日韩欧美不卡 | 久久黄色视 | 欧美精品一区二区三区久久久 | 国产色婷婷亚洲99精品小说 | 久久极品 | 狠狠色噜噜狠狠狠狠2021天天 | 精品国产乱码久久久久久婷婷 | 国产成人一区二区三区小说 | 国产精品99久久免费 | 麻豆91在线| 天天看片天天射 | 欧美成人性生活免费视频 | 国产欧美一区二区三区在线看 | 丰满少妇xbxb毛片日本视频 | 久久小草成人av免费观看 | 国产精品久久久久久久久婷婷 | 91精品国自产在线 | 日韩无码专区 | 日批视频在线免费看 | a级毛片国产 | 国产黄色大片在线观看 | 理论片亚洲| 无码里番纯肉h在线网站 | 亚洲精品美女久久久久网站 | 91久久国产露脸精品国产 | 亚洲精品乱码久久久久66国产成 | 久久免费少妇高潮99精品 | 99国产超薄肉色丝袜交足 | 国产精品最新乱视频二区 | 国产黄色影视 | 欧美骚视频| 亚洲精品乱码久久久久久蜜桃91 | 精品人伦一区二区三区蜜桃免费 | 国产精品人人爽人人做我的可爱 | 99视频久久| 国产第二专区 | 国产高清在线免费视频 | 亚洲 自拍 另类小说综合图区 | 古代中国春交性视频xxx | 欧美性色黄大片手机版 | 国产免费无遮挡吸奶头视频 | 少妇人妻精品一区二区 | 东京天堂热av | 国产裸体丰满白嫩大尺度尤物可乐 | 国产黑丝一区 | 东南亚末成年videos | 欧美疯狂性受xxxxx喷水 | 久久久国产毛片 | 男女又爽又黄 | 久久精品丝袜高跟鞋 | 国产亚洲精品久久久91 | 日本老头xxxx视频 | 久热中文字幕无码视频 | 亚洲一二三四五 | 天堂在线观看av | 亚洲aaaaa特级 | 奇米影视欧美 | 中文字幕日韩精品有码视频 | 国产粉嫩在线 | 激情综合丁香五月 | 奇米影视在线视频 | 亚洲高清精品视频 | 69中国xxxxxxxxx96| 涩色视频| 蜜桃av导航| 国产综合精品一区二区三区 | 久久久久久999 | 在线有码视频 | 一级免费看 | 亚洲色图网友自拍 | 欧美日韩视频一区二区 | 女人精69xxxxxx免费 | 亚洲乱妇老熟女爽到高潮的片 | 香蕉视频啪啪 | 中文字幕人妻无码系列第三区 | 一本无码av中文出轨人妻 | 狠狠躁夜夜躁人人爽天天 | 99精品国产在热久久无码 | 国产精品裸体一区二区三区 | 国产精品污www一区二区三区 | 午夜视频色| 欧美三级一级 | 国产精品久久久久久久久齐齐 | 免费一级肉体全黄毛片 | 欧美亚洲精品在线观看 | 久久99精品国产麻豆婷婷洗澡 | 免费va人成视频网站全 | 91精品国产91久久久久久久久久久久 | 全黄性性激高免费视频 | 欧美大肥婆bbbww欧出奶水 | 国产成人精品无码免费看夜聊软件 | 欧美一区二区三区 | 夜鲁鲁鲁夜夜综合视频欧美 | 国产精品久久人妻无码网站一区 | 另类激情综合 | 女同三级在线观看bd | 狠狠色综合久久婷婷色天使 | 久久女同互慰一区二区三区 | 色综合天天综合网国产成人网 | 66av99精品福利视频在线 | 91精品国产福利一区二区三区 | 青青草免费公开视频 | 草久久 | 中国丰满人妻videoshd | 国产一级片网址 | 久久久久女人精品毛片九一韩国 | 美女极度色诱图片www视频 | 国产情侣呻吟对白高潮 | 综合色婷婷一区二区亚洲欧美国产 | 国产国产人免费人成免费 | 国产人与禽zoz0性伦免费视频 | 精品久久人妻av中文字幕 | 少妇裸体啪啪激情高潮 | 国产午夜在线视频 | 99re这里只有精品在线观看 | 99极品视频| 婷婷久久综合九色综合 | 九久久久久| 精品欧美一区二区在线观看 | 国产露脸4p交换视频观看 | 免费在线观看小视频 | 宅女噜噜66国产精品观看免费 | 成人av动漫在线观看 | 久久久久久一 | 亚洲国色天香卡2卡3卡4 | 无码人妻精品一区二区三区免费 | 青草影院内射中出高潮 | 精品人伦一区二区三电影 | 91视频播放器 | 91精品国产乱码久久久久 | 色噜噜狠狠色综合中国 | 美女av一区| 377p欧洲日本亚洲大胆噜噜 | 欧美日韩一区二区三区四区五区 | 天天干天天射天天爽 | 久久久久爽人综合网站 | 日韩av片观看 | 四虎国产精品永久在线国在线 | 朝鲜女人大白屁股ass孕交 | 91免费精品 | 国产爆乳美女娇喘呻吟 | 欧美亚洲国产一区二区三区 | 天天爽天天爽天天爽 | 亚洲精选一区二区三区 | 好吊妞视频788gao在线观看 | 台湾佬成人中文网222vvv | 久久精品手机观看 | 中国老女人内谢69xxxx | 日本热久久 | 皇后高h喷水荡肉np 黄av在线免费观看 黄大色黄大片女爽一次 | 久久中文字幕无码专区 | 亚洲国产久 | 91精品免费 | 亚洲无线码在线一区观看 | 波多野结衣不打码视频 | 亚洲成a人片在线观看天堂无码 | 涩涩视频免费看 | 五级毛片| 久久久久久亚洲精品a片成人 | 午夜成人理论无码电影在线播放 | 91精品国产欧美一区二区 | 国产麻豆一区二区三区在线观看 | 综合激情婷婷 | 成人国产精品久久久春色 | 国产色综合天天综合网 | 无码专区一va亚洲v专区在线 | √新版天堂资源在线资源 | 精品国产乱码久久久久久1区2区 | 在火车千女人毛片看看 | 老色鬼a∨在线视频在线观看 | 无码日韩人妻精品久久蜜桃 | 国产日韩av一区二区 | 精品国产老女人乱码 | 无套日出白浆 | 久久久男女 | 一边添奶一边添p好爽视频 欧美 变态 另类 人妖 | 男女性生活毛片 | 性盈盈影院中文字幕 | 久久国产精品嫩草影院的使用方法 | 国产在线观看一区二区三区 | 激情久久一区二区三区 | 国产黄色毛片视频 | 婷婷色吧 | 无码国产精品一区二区免费i6 | 91xxx| 亚洲福利在线观看 | 台湾a级艳片潘金莲 | 亚洲福利网站 | 国产精品亚韩精品无码a在线 | 青青草精品在线 | 特黄特色特刺激免费播放 | av网址网站 | 国产一区二区三区久久久 | 亚洲色精品aⅴ一区区三区 国产黄大片在线观看 | 国产一区 在线播放 | 女生高潮视频在线观看 | 人人妻人人澡人人爽精品欧美 | 97久久久久久 | 综合av第一页 | 日韩精品一区二区三区中文 | 黄色一级片在线播放 | 国产乱人伦精品一区二区 | 无遮挡男女激烈动态图 | 国产卡一卡二卡三无线乱码新区 | 久久精品国产清自在天天线 | 国产又黄又猛又粗又爽视频 | 国产露脸久久高潮 | 夜夜操影视 | 玖玖爱在线精品视频 | 毛片一区| 国产电影一区二区三区 | 成年人视频网址 | 少妇性荡欲午夜性开放视频剧场 | 99国产精品久久久久久久 | 骚虎视频在线观看 | 国内精品久久久久久久久电影网 | 闷骚老干部cao个爽 萌白酱国产一区二区 | 久久亚洲高潮流白浆av软件 | 大肉大捧一进一出好爽视频mba | 国产性猛交xx乱老孕妇 | jizz在线免费观看 | 日韩三级欧美 | 国产在线精品成人一区二区 | 精品国产乱码久久久久久88av | 黄色国产在线播放 | 中文在线观看视频 | 成人动漫在线观看免费 | 亚洲欧美综合久久 | 欧美女人性生活视频 | 日韩三级网址 | 91网在线| 波多野结衣激情视频 | 国产伦精品一区二区三区免费观看 | 四虎在线免费观看视频 | 国产香蕉视频在线播放 | 亚洲精品乱码久久久久久蜜桃动漫 | 夜色资源ye321 在线观看 | 男人天堂怡红院 | 久久久久久久久久一毛喷水 | 中文字幕女优 | 日本在线网站 | 亚洲字幕在线观看 | 亚洲自拍色 | 久久亚洲天堂网 | 新超碰在线 | 久草久热 | 中文字幕第4页 | 国产亚洲精品久久久久久 | 日本一区免费 | 亚洲图片欧美另类 | 日韩欧美一区二区三区四区 | 全黄h全肉边做边吃奶视频 熟妇人妻av无码一区二区三区 | 日韩九九九 | 激情小说在线观看 | 无码人妻视频一区二区三区 | 麻豆天天躁天天揉揉av | 久久久久久人妻精品一区 | 青草青草视频 | 色夜av | 日韩国产一区二区 | 国产精品另类激情久久久免费 | 法国伦理少妇愉情 | 美女自卫慰免费视频www免费 | 91久久极品少妇韩国 | 国产一区二区三区免费看 | 国产精品美女久久久久久久久 | 99re6热在线精品视频播放 | 在线观看久 | 欧美日韩福利视频 | 久草在线观看资源 | 久久久久久久久久免费视频 | 二区影院 | 欧美性色黄大片在线观看 | 欧美黑吊大战白妞 | 欧美精品与人动性物交免费看 | 久久久日韩精品一区二区 | 18中国xxxxxⅹxxx96 | 国产精品xx| 欧美成人综合色 | 国产一级黄色录像 | 久久综合九色综合久99 | 国产美女裸身网站免费观看视频 | 亚洲一卡久久 | 欧美乱妇高清无乱码在线观看 | 婷婷狠狠久久久一本精品 | 老头老夫妇自拍性tv | 青草久久久 | 欧美成人黑人xx视频免费观看 | av视| 国产美女精品人人做人人爽 | 久久视频在线视频 | www.五月天婷婷.com | 在线国产观看 | 久久久久久久久久久久中文字幕 | 久久久久噜噜噜亚洲熟女综合 | 国产男女在线观看 | 91插插插插 | 麻豆果冻传媒2021精品传媒一区下载 | 四季av中文字幕一区 | 国产精品二区一区二区aⅴ 国产精品粉嫩懂色av | 国产最爽的乱淫视频媛 | 国产suv精品一区二区四 | 人妻三级日本三级日本三级极 | 99久久精品国产一区二区成人 | 亚洲va欧美va人人爽 | 天天射日| 日韩精品在线视频免费观看 | 亚洲大片免费看 | 久久成人久久爱 | 国产女同疯狂作爱系列69 | 精品国产乱码久久久人妻 | 国产高颜值大学生情侣酒店 | 国产成人精品视频网站 | av久久久久久 | 美丽肉奴隷1986在线观看 | 一区二区三区福利视频 | 六月天婷婷 | 日日躁夜夜躁白天躁晚上 | av手机| 交换一区二区三区va在线 | 国产激情视频在线观看 | 亚洲熟女www一区二区三区 | 亚洲一区二区三区四区五区午夜 | 日日骚av| 一本大道东京热无码一区 | 日韩av三级在线 | 国产性在线 | 人妻少妇久久久久久97人妻 | 色翁荡熄又大又硬又粗又视频图片 | 香港三级澳门三级人妇99 | 亚洲另类天堂 | 中文字幕人妻少妇引诱隔壁 | 高潮射精日本韩国在线播放 | 日本一区二区三区视频在线播放 | 黄色片毛片 | 国产69精品久久 | 欧美性群另类交 | 国产一区在线播放 | 海角国产乱辈乱精品视频 | 国产亚洲精品久久久久秋霞 | 电梯男女做爰视频 | 国产在热线精品视频 | 中文字幕av一区二区三区高 | 久久精品女人天堂av | www91在线 | av片亚洲| 日韩在线播放视频 | 久久人人97超碰精品888 | 国产精品第四页 | 男女啪啪资源 | 国产免费最爽的乱淫视频a 国产免国产免费 | 24小时日本在线www免费的 | 男人的天堂免费av | 91丨国产| 日韩a∨精品日韩在线观看 日韩avav | 人妻少妇久久久久久97人妻 | 精品国产乱码久久久久久久软件 | 99国产精品国产免费观看 | 26uuu久久噜噜噜噜 | 小sao货水好多真紧h视频, | 日韩三区四区 | 欧美午夜片欧美片在线观看 | 中文字幕一区二区人妻性色 | 91中文字幕永久在线 | 国产成人精品午夜视频' | 日本无遮挡真人祼交视频 | 在线观看中文字幕av | 午夜精品久久久久久99热小说 | 亚洲精品白浆高清久久久久久 | 国产另类ts人妖高潮 | 成人免费看片39 | 久久婷婷五月综合色和啪 | 免费看毛片在线观看 | 色爱区综合 | 黄色的网站在线免费观看 | 一本一本久久a久久精品综合妖精 | 麻豆网神马久久人鬼片 | 国产成人精品午夜视频' | 亚洲欧美国产精品久久久久久久 | 五月婷婷综合久久 | 国产黄色片免费 | a级毛片特级毛片 | 成人三及片 | 日韩人妻无码免费视频一区二区三区 | 中文字幕av亚洲精品一部二部 | 国产精品久久久久久久龚玥菲 | 亚洲精品国产成人 | 少妇特黄a片一区二区三区 精品香蕉一区二区三区 | 人与善性猛交xxxx视频 | 操韩国美女 | 亚洲综合视频网站 | 久久日本三级韩国三级 | 999久久久免费精品国产 | 国产成人无遮挡在线视频 | 日韩手机看片 | 久久久www成人免费毛片女 | 色诱av手机版 | 久久99国产精品女同 | 欧美三区| 国产欧美一区二区三区沐欲 | 人成亚洲 | 黄色a级大片 | 欧美在线视频不卡 | 亚洲天堂一区二区 | 色阁av| 欧美一区国产一区 | 精品视频一区二区 | 狂野3p欧美激情性xxxx | 理论片一区 | 他也色在线 | 欧美精品一区二区三区四区在线 | 日本韩国在线播放 | 欧美日韩在线一区二区 | 亚洲男人天堂网址 | 亚洲日本va中文字幕 | 日韩精品视频免费专区在线播放 | 国产女主播在线观看 | 国产第七页 | 999偷拍精品视频 | 91久久中文字幕 | 欧美无砖专区免费 | 意大利性荡欲xxxxxx | 又色又爽又黄18网站 | 天天鲁一鲁摸一摸爽一爽 | 在线播放亚洲第一字幕 | 午夜性视频国产牛牛视频 | 亚洲精品少妇久久久久久 | 国产精品夜夜春夜夜爽久久老牛 | 成人国产精品久久久春色 | 久久网站视频 | 欧美精品在线观看一区二区 | 免费观看久久久 | 毛片免费视频观看 | 91超碰caoporm国产香蕉 | 国产人妻aⅴ色偷 | 久草在线中文888 | 国产小视频在线观看 | 久热国产视频 | 天堂а√8在线最新版在线 大地资源中文第三页 | 久久天天躁夜夜躁狠狠i女人 | 午夜精品久久久久久久99 | 亚洲激情图片 | 台湾chinesehdxxxx少妇 | 日韩丰满少妇无码内射 | 亚洲视频在线观看 | 免费观看交性大片 | 国产成人精品久久 | 色综合天天综合网天天狠天天 | 91精品久久久久久久久久入口 | 欧美色一区二区三区在线观看 | 亚洲欧美精品综合在线观看 | 台湾绝版午夜裸体写真秀 | 欧美做爰xxxⅹ性欧美大片 | 成人vr视频在线观看 | 久久99国产精品久久99果冻传媒 | 天堂新版8中文在线8 | 夜夜春很很躁夜夜躁 | 亚洲精品美女久久久久99 | 国产一级桃视频播放 | 久久精品一区二区 | 国产精品欧美综合亚洲 | 人人妻人人澡人人爽人人精品浪潮 | 亚洲国产精品女主播 | 香港三级毛片 | 欧美69式互添视频在线 | 97在线观看永久免费视频 | 国产在线国偷精品产拍免费观看 | 日日干夜夜艹 | 国产成人免费观看视频 | 亚洲精品久久久久久一区二区 | 国产亚洲精品久久19p | 日韩精品一区二区三区亚洲综合 | 国产精品 高清 尿 小便 嘘嘘 | jizz日本大全| 国产人妖视频一区二区 | 2020亚洲视频 | 亚洲一区二区久久 | 少妇性l交大片免费观看冫 少妇性l交大片免费快色 | 丰满熟女高潮毛茸茸欧洲 | 国产特黄aaa大片免费观看 | 理论片毛片| 糟蹋小少妇17p | 国产波多野结衣 | 国产无套粉嫩白浆内谢的出处 | 丁香社区五月天 | 全毛片| 美女疯狂连续喷潮视频 | 久久久久久久99精品免费观看 | 午夜精品久久久久久久喷水 | 久久精品aⅴ无码中文字字幕蜜桃 | 国产一区二区三区视频在线 | 久久网中文字幕 | 中文字字幕在线中文无码 | 精品va久久久噜噜久久软件 | 中国黄色毛片视频 | 91精品国产91久久久久福利 | 玉米视频成人免费看 | 亚洲午夜在线视频 | 做爰猛烈叫床91 | 亚日韩欧美 | 国产3级在线 | 午夜精品久久久久久久 | 国产一级特黄aa大片出来精子 | 一区二区三区四区在线视频 | 色丁香在线 | 人妻夜夜爽天天爽爽一区 | 黄色国产精品 | 成人国产欧美 | 人操人视频 | 亚洲精品久久久打桩机小说 | 亚洲伊人久久大香线蕉综合图片 | 麻豆理论片 | 国产免费又黄又爽又刺激蜜月al | 成人激烈床戏免费观看网站 | 一级免费大片 | 亚洲 高清 成人 动漫 | 国产精品久久久天天影视 | 极品在线播放 | 99re在线视频观看 | 国产精品国产亚洲精品看不卡 | 色在线影院 | 爱情岛av亚洲论坛自拍品质 | 国产伦精品一区二区三区千人斩 | 日韩中文字幕亚洲精品欧美 | 日本激情吻胸吃奶呻吟视频 | 永久免费的av在线电影网 | 在线观看黄网 | 性视屏 | 日本特黄特色aaa大片免费 | 国产精品嫩| 图片区 小说区 区 亚洲五月 | 久久夜色精品国产欧美乱极品 | 国产一及毛片 | 九九热国产精品视频 | 国产精品欧美精品 | 天堂少妇| 无码内射中文字幕岛国片 | 日韩欧美在线一区二区 | 中文字幕第 | 99久久国产综合精品麻豆 | 色噜噜亚洲精品中文字幕 | 中国凸偷窥xxxx自由视频妇科 | 91艹逼| av无码免费永久在线观看 | 天天av天天av天天透 | 欧美日韩一区二区三 | 亚洲一区二区三区乱码aⅴ 亚洲一区二区三区日本久久九 | 日本少妇xxx做受 | 日日天日日夜日日摸 | 国产在线精品一区二区高清不卡 | 黄瓜视频在线免费观看 | www.youjizz.com在线 | 欧美性开放视频 | 久久一本久综合久久爱 | 翘臀后进少妇大白嫩屁股91 |