文章編號:11439時間:2024-09-30人氣:
在構(gòu)建高性能、可擴展的 Java 應(yīng)用程序時,充分利用多線程至關(guān)重要。如果不慎使用,線程也可能成為性能瓶頸,甚至導致不可預(yù)測的行為。
suspendThread 方法是一種過時的線程管理技術(shù),在 Java 9 及更高版本中已被棄用。它通過暫停線程的執(zhí)行來凍結(jié)線程,但在某些情況下可能導致死鎖和不可預(yù)測的行為。因此,在現(xiàn)代 Java 應(yīng)用程序中使用 suspendThread 并不是一個好習慣。
有幾種現(xiàn)代技術(shù)可以用來高效地管理線程,避免了 suspendThread 的缺點。以下是一些常見的方法:
wait() 和 notify() 方法允許線程等待特定條件滿足后再繼續(xù)執(zhí)行。這對于實現(xiàn)生產(chǎn)者-消費者模式和同步線程訪問共享資源非常有用。
Lock 和 Condition 類提供了一種更靈活的方式來管理線程同步。它們允許線程在獲取鎖后執(zhí)行某些操作,并在特定條件滿足時釋放鎖。
CountDownLatch 類用于等待一組線程完成特定任務(wù)。它提供了一個計數(shù)器,在所有線程完成任務(wù)后減為零,從而允許主線程繼續(xù)執(zhí)行。
Semaphore 類用于限制對共享資源的并發(fā)訪問。它允許指定資源的最大訪問數(shù),并強制線程在訪問資源之前獲取許可證。
假設(shè)我們要構(gòu)建一個簡單的生產(chǎn)者-消費者應(yīng)用程序,其中生產(chǎn)者線程將數(shù)據(jù)放入隊列,而消費者線程將數(shù)據(jù)從隊列中取出。我們可以使用 Lock 和 Condition 如下實現(xiàn)它:
java import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Condition;一、線程的概念一般來說,我們把正在計算機中執(zhí)行的程序叫做進程(Process) ,而不將其稱為程序(Program)。 所謂線程(Thread),是進程中某個單一順序的控制流。 新興的操作系統(tǒng),如Mac,Windows NT,Windows 95等,大多采用多線程的概念,把線程視為基本執(zhí)行單位。 線程也是Java中的相當重要的組成部分之一。 甚至最簡單的Applet也是由多個線程來完成的。 在Java中,任何一個Applet的paint()和update()方法都是由AWT(Abstract Window Toolkit)繪圖與事件處理線程調(diào)用的,而Applet 主要的里程碑方法——init(),start(),stop()和destory()——是由執(zhí)行該Applet的應(yīng)用調(diào)用的。 單線程的概念沒有什么新的地方,真正有趣的是在一個程序中同時使用多個線程來完成不同的任務(wù)。 某些地方用輕量進程(Lightweig ht Process)來代替線程,線程與真正進程的相似性在于它們都是單一順序控制流。 然而線程被認為輕量是由于它運行于整個程序的上下文內(nèi),能使用整個程序共有的資源和程序環(huán)境。 作為單一順序控制流,在運行的程序內(nèi)線程必須擁有一些資源作為必要的開銷。 例如,必須有執(zhí)行堆棧和程序計數(shù)器。 在線程內(nèi)執(zhí)行的代碼只在它的上下文中起作用,因此某些地方用執(zhí)行上下文來代替線程。 二、線程屬性為了正確有效地使用線程,必須理解線程的各個方面并了解Java 實時系統(tǒng)。 必須知道如何提供線程體、線程的生命周期、實時系統(tǒng)如 何調(diào)度線程、線程組、什么是幽靈線程(Demo nThread)。 (1)線程體所有的操作都發(fā)生在線程體中,在Java中線程體是從Thread類繼承的run()方法,或?qū)崿F(xiàn)Runnable接口的類中的run()方法。 當線程產(chǎn)生并初始化后,實時系統(tǒng)調(diào)用它的run()方法。 run()方法內(nèi)的代碼實現(xiàn)所產(chǎn)生線程的行為,它是線程的主要部分。 (2)線程狀態(tài)附圖表示了線程在它的生命周期內(nèi)的任何時刻所能處的狀態(tài)以及引起狀態(tài)改變的方法。 這圖并不是完整的有限狀態(tài)圖,但基本概括了線程中比較感興趣和普遍的方面。 以下討論有關(guān)線程生命周期以此為據(jù)。 ●新線程態(tài)(New Thread)產(chǎn)生一個Thread對象就生成一個新線程。 當線程處于新線程狀態(tài)時,僅僅是一個空線程對象,它還沒有分配到系統(tǒng)資源。 因此只能啟動或終止它。 任何其他操作都會引發(fā)異常。 ●可運行態(tài)(Runnable)start()方法產(chǎn)生運行線程所必須的資源,調(diào)度線程執(zhí)行,并且調(diào)用線程的run()方法。 在這時線程處于可運行態(tài)。 該狀態(tài)不稱為運行態(tài)是因為這時的線程并不總是一直占用處理機。 特別是對于只有一個處理機的PC而言,任何時刻只能有一個處于可運行態(tài)的線程占用處理 機。 Java通過調(diào)度來實現(xiàn)多線程對處理機的共享。 ●非運行態(tài)(Not Runnable)當以下事件發(fā)生時,線程進入非運行態(tài)。 ①suspend()方法被調(diào)用;②sleep()方法被調(diào)用;③線程使用wait()來等待條件變量;④線程處于I/O等待。 ●死亡態(tài)(Dead)當run()方法返回,或別的線程調(diào)用stop()方法,線程進入死亡態(tài) 。 通常Applet使用它的stop()方法來終止它產(chǎn)生的所有線程。 (3)線程優(yōu)先級雖然我們說線程是并發(fā)運行的。 然而事實常常并非如此。 正如前面談到的,當系統(tǒng)中只有一個CPU時,以某種順序在單CPU情況下執(zhí)行多線程被稱為調(diào)度(scheduling)。 Java采用的是一種簡單、固定的調(diào)度法,即固定優(yōu)先級調(diào)度。 這種算法是根據(jù)處于可運行態(tài)線程的相對優(yōu)先級來實行調(diào)度。 當線程產(chǎn)生時,它繼承原線程的優(yōu)先級。 在需要時可對優(yōu)先級進行修改。 在任何時刻,如果有多條線程等待運行,系統(tǒng)選擇優(yōu)先級最高的可運行線程運行。 只有當它停止、自動放棄、或由于某種原因成為非運行態(tài)低優(yōu)先級的線程才能運行。 如果兩個線程具有相同的優(yōu)先級,它們將被交替地運行。 Java實時系統(tǒng)的線程調(diào)度算法還是強制性的,在任何時刻,如果一個比其他線程優(yōu)先級都高的線程的狀態(tài)變?yōu)榭蛇\行態(tài),實時系統(tǒng)將選擇該線程來運行。 (4)幽靈線程任何一個Java線程都能成為幽靈線程。 它是作為運行于同一個進程內(nèi)的對象和線程的服務(wù)提供者。 例如,HotJava瀏覽器有一個稱為 后臺圖片閱讀器的幽靈線程,它為需要圖片的對象和線程從文件系統(tǒng)或網(wǎng)絡(luò)讀入圖片。 幽靈線程是應(yīng)用中典型的獨立線程。 它為同一應(yīng)用中的其他對象和線程提供服務(wù)。 幽靈線程的run()方法一般都是無限循環(huán),等待服務(wù)請求。 (5)線程組每個Java線程都是某個線程組的成員。 線程組提供一種機制,使得多個線程集于一個對象內(nèi),能對它們實行整體操作。 譬如,你能用一個方法調(diào)用來啟動或掛起組內(nèi)的所有線程。 Java線程組由ThreadGroup類實現(xiàn)。 當線程產(chǎn)生時,可以指定線程組或由實時系統(tǒng)將其放入某個缺省的線程組內(nèi)。 線程只能屬于一個線程組,并且當線程產(chǎn)生后不能改變它所屬的線程組。 三、多線程程序?qū)τ诙嗑€程的好處這就不多說了。 但是,它同樣也帶來了某些新的麻煩。 只要在設(shè)計程序時特別小心留意,克服這些麻煩并不算太困難。 (1)同步線程許多線程在執(zhí)行中必須考慮與其他線程之間共享數(shù)據(jù)或協(xié)調(diào)執(zhí)行狀態(tài)。 這就需要同步機制。 在Java中每個對象都有一把鎖與之對應(yīng)。 但Java不提供單獨的lock和unlock操作。 它由高層的結(jié)構(gòu)隱式實現(xiàn), 來保證操作的對應(yīng)。 (然而,我們注意到Java虛擬機提供單獨的monito renter和monitorexit指令來實現(xiàn)lock和unlock操作。 )synchronized語句計算一個對象引用,試圖對該對象完成鎖操作, 并且在完成鎖操作前停止處理。 當鎖操作完成synchronized語句體得到執(zhí)行。 當語句體執(zhí)行完畢(無論正常或異常),解鎖操作自動完成。 作為面向對象的語言,synchronized經(jīng)常與方法連用。 一種比較好的辦法是,如果某個變量由一個線程賦值并由別的線程引用或賦值,那么所有對該變量的訪問都必須在某個synchromized語句或synchronized方法內(nèi)。 現(xiàn)在假設(shè)一種情況:線程1與線程2都要訪問某個數(shù)據(jù)區(qū),并且要求線程1的訪問先于線程2, 則這時僅用synchronized是不能解決問題的。 這在Unix或Windows NT中可用Simaphore來實現(xiàn)。 而Java并不提供。 在Java中提供的是wait()和notify()機制。 使用如下:synchronized method-1(…){ call by thread 1.‖access data area;available=true;notify()}synchronized method-2(…){‖call by thread (!available)try{wait();‖wait for notify().}catch (Interrupted Exception e){}‖access data area}其中available是類成員變量,置初值為false。 如果在method-2中檢查available為假,則調(diào)用wait()。 wait()的作用是使線程2進入非運行態(tài),并且解鎖。 在這種情況下,method-1可以被線程1調(diào)用。 當執(zhí)行notify()后。 線程2由非運行態(tài)轉(zhuǎn)變?yōu)榭蛇\行態(tài)。 當method-1調(diào)用返回后。 線程2可重新對該對象加鎖,加鎖成功后執(zhí)行wait()返回后的指令。 這種機制也能適用于其他更復(fù)雜的情況。 (2)死鎖如果程序中有幾個競爭資源的并發(fā)線程,那么保證均衡是很重要的。 系統(tǒng)均衡是指每個線程在執(zhí)行過程中都能充分訪問有限的資源。 系統(tǒng)中沒有餓死和死鎖的線程。 Java并不提供對死鎖的檢測機制。 對大多數(shù)的Java程序員來說防止死鎖是一種較好的選擇。 最簡單的防止死鎖的方法是對競爭的資源引入序號,如果一個線程需要幾個資源,那么它必須先得到小序號的資源,再申請大序號的資源。 四、線程和進程的比較進程是資源分配的基本單位。 所有與該進程有關(guān)的資源,都被記錄在進程控制塊PCB中。 以表示該進程擁有這些資源或正在使用它們。 另外,進程也是搶占處理機的調(diào)度單位,它擁有一個完整的虛擬地址空間。 與進程相對應(yīng),線程與資源分配無關(guān),它屬于某一個進程,并與進程內(nèi)的其他線程一起共享進程的資源。 當進程發(fā)生調(diào)度時,不同的進程擁有不同的虛擬地址空間,而同一進程內(nèi)的不同線程共享同一地址空間。 線程只由相關(guān)堆棧(系統(tǒng)棧或用戶棧)寄存器和線程控制表TCB組成。 寄存器可被用來存儲線程內(nèi)的局部變量,但不能存儲其他線程的相關(guān)變量。 發(fā)生進程切換與發(fā)生線程切換時相比較,進程切換時涉及到有關(guān)資源指針的保存以及地址空間的變化等問題;線程切換時,由于同不進程內(nèi)的線程共享資源和地址 空間,將不涉及資源信息的保存和地址變化問題,從而減少了操作系統(tǒng)的開銷時間。 而且,進程的調(diào)度與切換都是由操作系統(tǒng)內(nèi)核完成,而線程則既可由操作系統(tǒng)內(nèi) 核完成,也可由用戶程序進行。 五、線程的適用范圍典型的應(yīng)用 1.服務(wù)器中的文件管理或通信控制 2.前后臺處理 3.異步處理六、線程的執(zhí)行特性一個線程必須處于如下四種可能的狀態(tài)之一:初始態(tài):一個線程調(diào)用了new方法之后,并在調(diào)用start方法之前的所處狀態(tài)。 在初始態(tài)中,可以調(diào)用start和stop方法。 Runnable:一旦線程調(diào)用了start 方法,線程就轉(zhuǎn)到Runnable 狀態(tài),注意,如果線程處于Runnable狀態(tài),它也有可能不在運行,這是因為還有優(yōu)先級和調(diào)度問題。 阻塞/ NonRunnable:線程處于阻塞/NonRunnable狀態(tài),這是由兩種可能性造成的:要么是因掛起而暫停的,要么是由于某些原因而阻塞的,例如包括等待IO請求的完成。 退出:線程轉(zhuǎn)到退出狀態(tài),這有兩種可能性,要么是run方法執(zhí)行結(jié)束,要么是調(diào)用了stop方法。 最后一個概念就是線程的優(yōu)先級,線程可以設(shè)定優(yōu)先級,高優(yōu)先級的線程可以安排在低優(yōu)先級線程之前完成。 一個應(yīng)用程序可以通過使用線程中的方法setPriority(int),來設(shè)置線程的優(yōu)先級大小。 線程有5種基本操作: 派生:線程在進程內(nèi)派生出來,它即可由進程派生,也可由線程派生。 阻塞(Block):如果一個線程在執(zhí)行過程中需要等待某個事件發(fā)生,則被阻塞。 激活(unblock):如果阻塞線程的事件發(fā)生,則該線程被激活并進入就緒隊列。 調(diào)度(schedule):選擇一個就緒線程進入執(zhí)行狀態(tài)。 結(jié)束(Finish):如果一個線程執(zhí)行結(jié)束,它的寄存器上下文以及堆棧內(nèi)容等將被釋放。 七、線程的分類線程有兩個基本類型: 用戶級線程:管理過程全部由用戶程序完成,操作系統(tǒng)內(nèi)核心只對進程進行管理。 系統(tǒng)級線程(核心級線程):由操作系統(tǒng)內(nèi)核進行管理。 操作系統(tǒng)內(nèi)核給應(yīng)用程序提供相應(yīng)的系統(tǒng)調(diào)用和應(yīng)用程序接口API,以使用戶程序可以創(chuàng)建、執(zhí)行、撤消線程。 附:線程舉例1. SUN Solaris 2.3Solaris支持內(nèi)核線程、輕權(quán)進程和用戶線程。 一個進程可有大量用戶線程;大量用戶線程復(fù)用少量的輕權(quán)進程,輕權(quán)進程與內(nèi)核線程一一對應(yīng)。 用戶級線程在調(diào)用核心服務(wù)時(如文件讀寫),需要“捆綁(bound)”在一個LWP上。 永久捆綁(一個LWP固定被一個用戶級線程占用,該LWP移到LWP池之外)和臨時捆綁(從LWP池中臨時分配一個未被占用的LWP)。 在調(diào)用系統(tǒng)服務(wù)時,如果所有LWP已被其他用戶級線程所占用(捆綁),則該線程阻塞直到有可用的LWP。 如果LWP執(zhí)行系統(tǒng)線程時阻塞(如read()調(diào)用),則當前捆綁在LWP上的用戶級線程也阻塞。 ¨有關(guān)的C庫函數(shù)/* 創(chuàng)建用戶級線程 */int thr_create(void *stack_base, size_t stack_size,void *(*start_routine)(void *), void *arg, long flags,thread_t *new_thread_id);其中flags包括:THR_BOUND(永久捆綁), THR_NEW_LWP(創(chuàng)建新LWP放入LWP池),若兩者同時指定則創(chuàng)建兩個新LWP,一個永久捆綁而另一個放入LWP池。 2有關(guān)的系統(tǒng)調(diào)用 /* 在當前進程中創(chuàng)建LWP */int _lwp_create(ucontext_t *contextp, unsigned long flags,lwpid_t *new_lwp_id);/* 構(gòu)造LWP上下文*/void _lwp_makecontext(ucontext_t *ucp, void (*start_routine)( void *), void *arg,void *private, caddr_t stack_base, size_t stack_size);/* 注意:沒有進行“捆綁”操作的系統(tǒng)調(diào)用 */2. Windows NTNT線程的上下文包括:寄存器、核心棧、線程環(huán)境塊和用戶棧。 NT線程狀態(tài) (1) 就緒狀態(tài):進程已獲得除處理機外的所需資源,等待執(zhí)行。 (2) 備用狀態(tài):特定處理器的執(zhí)行對象,系統(tǒng)中每個處理器上只能有一個處于備用狀態(tài)的線程。 (3) 運行狀態(tài):完成描述表切換,線程進入運行狀態(tài),直到內(nèi)核搶先、時間片用完、線程終止或進行等待狀態(tài)。 (4) 等待狀態(tài):線程等待對象句柄,以同步它的執(zhí)行。 等待結(jié)束時,根據(jù)優(yōu)先級進入運行、就緒狀態(tài)。 (5) 轉(zhuǎn)換狀態(tài):線程在準備執(zhí)行而其內(nèi)核堆棧處于外存時,線程進入轉(zhuǎn)換狀態(tài);當其內(nèi)核堆棧調(diào)回內(nèi)存,線程進入就緒狀態(tài)。 (6) 終止狀態(tài):線程執(zhí)行完就進入終止狀態(tài);如執(zhí)行體有一指向線程對象的指針,可將線程對象重新初始化,并再次使用。 NT線程的有關(guān)APICreateThread()函數(shù)在調(diào)用進程的地址空間上創(chuàng)建一個線程,以執(zhí)行指定的函數(shù);返回值為所創(chuàng)建線程的句柄。 ExitThread()函數(shù)用于結(jié)束本線程。 SuspendThread()函數(shù)用于掛起指定的線程。 ResumeThread()函數(shù)遞減指定線程的掛起計數(shù),掛起計數(shù)為0時,線程恢復(fù)執(zhí)行。
線程的同步是Java多線程編程的難點,往往開發(fā)者搞不清楚什么是競爭資源、什么時候需要考慮同步,怎么同步等等問題,當然,這些問題沒有很明確的答案,但有些原則問題需要考慮,是否有競爭資源被同時改動的問題?對于同步,在具體的Java代碼中需要完成以下兩個操作:把競爭訪問的資源標識為private;同步哪些修改變量的代碼,使用synchronized關(guān)鍵字同步方法或代碼。
當然這不是唯一控制并發(fā)安全的途徑。
synchronized關(guān)鍵字使用說明synchronized只能標記非抽象的方法,不能標識成員變量。
為了演示同步方法的使用,構(gòu)建了一個信用卡賬戶,起初信用額為100w,然后模擬透支、存款等多個操作。
顯然銀行賬戶User對象是個競爭資源,而多個并發(fā)操作的是賬戶方法oper(int x),當然應(yīng)該在此方法上加上同步,并將賬戶的余額設(shè)為私有變量,禁止直接訪問。
工作原理線程是進程中的實體,一個進程可以擁有多個線程,一個線程必須有一個父進程。
線程不擁有系統(tǒng)資源,只有運行必須的一些數(shù)據(jù)結(jié)構(gòu);它與父進程的其它線程共享該進程所擁有的全部資源。
線程可以創(chuàng)建和撤消線程,從而實現(xiàn)程序的并發(fā)執(zhí)行。
一般,線程具有就緒、阻塞和運行三種基本狀態(tài)。
在多中央處理器的系統(tǒng)里,不同線程可以同時在不同的中央處理器上運行,甚至當它們屬于同一個進程時也是如此。
大多數(shù)支持多處理器的操作系統(tǒng)都提供編程接口來讓進程可以控制自己的線程與各處理器之間的關(guān)聯(lián)度(affinity)。
有時候,線程也稱作輕量級進程。
就象進程一樣,線程在程序中是獨立的、并發(fā)的執(zhí)行路徑,每個線程有它自己的堆棧、自己的程序計數(shù)器和自己的局部變量。
但是,與分隔的進程相比,進程中的線程之間的隔離程度要小。
它們共享內(nèi)存、文件句柄和其它每個進程應(yīng)有的狀態(tài)。
進程可以支持多個線程,它們看似同時執(zhí)行,但互相之間并不同步。
一個進程中的多個線程共享相同的內(nèi)存地址空間,這就意味著它們可以訪問相同的變量和對象,而且它們從同一堆中分配對象。
盡管這讓線程之間共享信息變得更容易,但您必須小心,確保它們不會妨礙同一進程里的其它線程。
Java 線程工具和 API看似簡單。
但是,編寫有效使用線程的復(fù)雜程序并不十分容易。
因為有多個線程共存在相同的內(nèi)存空間中并共享相同的變量,所以您必須小心,確保您的線程不會互相干擾。
線程屬性為了正確有效地使用線程,必須理解線程的各個方面并了解Java 實時系統(tǒng)。
必須知道如何提供線程體、線程的生命周期、實時系統(tǒng)如 何調(diào)度線程、線程組、什么是幽靈線程(Demo nThread)。
線程體所有的操作都發(fā)生在線程體中,在Java中線程體是從Thread類繼承的run()方法,或?qū)崿F(xiàn)Runnable接口的類中的run()方法。
當線程產(chǎn)生并初始化后,實時系統(tǒng)調(diào)用它的run()方法。
run()方法內(nèi)的代碼實現(xiàn)所產(chǎn)生線程的行為,它是線程的主要部分。
線程狀態(tài)附圖表示了線程在它的生命周期內(nèi)的任何時刻所能處的狀態(tài)以及引起狀態(tài)改變的方法。
這圖并不是完整的有限狀態(tài)圖,但基本概括了線程中比較感興趣和普遍的方面。
以下討論有關(guān)線程生命周期以此為據(jù)。
●新線程態(tài)(New Thread)產(chǎn)生一個Thread對象就生成一個新線程。
當線程處于新線程狀態(tài)時,僅僅是一個空線程對象,它還沒有分配到系統(tǒng)資源。
因此只能啟動或終止它。
任何其他操作都會引發(fā)異常。
例如,一個線程調(diào)用了new方法之后,并在調(diào)用start方法之前的處于新線程狀態(tài),可以調(diào)用start和stop方法。
●可運行態(tài)(Runnable)start()方法產(chǎn)生運行線程所必須的資源,調(diào)度線程執(zhí)行,并且調(diào)用線程的run()方法。
在這時線程處于可運行態(tài)。
該狀態(tài)不稱為運行態(tài)是因為這時的線程并不總是一直占用處理機。
特別是對于只有一個處理機的PC而言,任何時刻只能有一個處于可運行態(tài)的線程占用處理 機。
Java通過調(diào)度來實現(xiàn)多線程對處理機的共享。
注意,如果線程處于Runnable狀態(tài),它也有可能不在運行,這是因為還有優(yōu)先級和調(diào)度問題。
●阻塞/非運行態(tài)(Not Runnable)當以下事件發(fā)生時,線程進入非運行態(tài)。
①suspend()方法被調(diào)用;②sleep()方法被調(diào)用;③線程使用wait()來等待條件變量;④線程處于I/O請求的等待。
●死亡態(tài)(Dead)當run()方法返回,或別的線程調(diào)用stop()方法,線程進入死亡態(tài)。
通常Applet使用它的stop()方法來終止它產(chǎn)生的所有線程。
線程的本操作:派生:線程在進程內(nèi)派生出來,它即可由進程派生,也可由線程派生。
阻塞(Block):如果一個線程在執(zhí)行過程中需要等待某個事件發(fā)生,則被阻塞。
激活(unblock):如果阻塞線程的事件發(fā)生,則該線程被激活并進入就緒隊列。
調(diào)度(schedule):選擇一個就緒線程進入執(zhí)行狀態(tài)。
結(jié)束(Finish):如果一個線程執(zhí)行結(jié)束,它的寄存器上下文以及堆棧內(nèi)容等將被釋放。
圖2 線程的狀態(tài)與操作線程的另一個執(zhí)行特性是同步。
線程中所使用的同步控制機制與進程中所使用的同步控制機制相同。
線程優(yōu)先級雖然我們說線程是并發(fā)運行的。
然而事實常常并非如此。
正如前面談到的,當系統(tǒng)中只有一個CPU時,以某種順序在單CPU情況下執(zhí)行多線程被稱為調(diào)度(scheduling)。
Java采用的是一種簡單、固定的調(diào)度法,即固定優(yōu)先級調(diào)度。
這種算法是根據(jù)處于可運行態(tài)線程的相對優(yōu)先級來實行調(diào)度。
當線程產(chǎn)生時,它繼承原線程的優(yōu)先級。
在需要時可對優(yōu)先級進行修改。
在任何時刻,如果有多條線程等待運行,系統(tǒng)選擇優(yōu)先級最高的可運行線程運行。
只有當它停止、自動放棄、或由于某種原因成為非運行態(tài)低優(yōu)先級的線程才能運行。
如果兩個線程具有相同的優(yōu)先級,它們將被交替地運行。
Java實時系統(tǒng)的線程調(diào)度算法還是強制性的,在任何時刻,如果一個比其他線程優(yōu)先級都高的線程的狀態(tài)變?yōu)榭蛇\行態(tài),實時系統(tǒng)將選擇該線程來運行。
一個應(yīng)用程序可以通過使用線程中的方法setPriority(int),來設(shè)置線程的優(yōu)先級大小。
有線程進入了就緒狀態(tài),需要有線程調(diào)度程序來決定何時執(zhí)行,根據(jù)優(yōu)先級來調(diào)度。
線程中的join()可以用來邀請其他線程先執(zhí)行(示例代碼如下);publicclassJoin01implementsRunnable{publicstaticvoidmain(String[]args){for(inti=0;i<20;i++){if(i==5){Join01j=newJoin01();Threadt=newThread(j);(被邀請先執(zhí)行的線程.);();try{//邀請這個線程,先執(zhí)行();}catch(InterruptedExceptione){();}}(沒被邀請的線程。
+(i+1));}}publicvoidrun(){for(inti=0;i<10;i++){(()()+(i+1));}}}yield()告訴系統(tǒng)把自己的CPU時間讓掉,讓其他線程或者自己運行,示例代碼如下;publicclassYield01{publicstaticvoidmain(String[]args){YieldFirstyf=newYieldFirst();YieldSecondys=newYieldSecond();YieldThirdyt=newYieldThird();();();();}}classYieldFirstextendsThread{@Overridepublicvoidrun(){for(inti=0;i<10;i++){(第一個線程第+(i+1)+次運行.);//讓當前線程暫停yield();}}}classYieldSecondextendsThread{@Overridepublicvoidrun(){for(inti=0;i<10;i++){(第二個線程第+(i+1)+次運行.);//讓當前線程暫停yield(); ,僅適用于Sun Solaris操作系統(tǒng)。
所以UNIX International線程也常被俗稱為Solaris線程。
1.創(chuàng)建線程intthr_create(void*stack_base,size_tstack_size,void*(*start_routine)(void*),void*arg,longflags,thread_t*new_thr);2.等待線程intthr_join(thread_twait_for,thread_t*dead,void**status);3.掛起線程intthr_suspend(thread_tthr);4.繼續(xù)線程intthr_continue(thread_tthr);5.退出線程voidthr_exit(void*status);6.返回當前線程的線程標識符thread_tthr_self(void);POSIX線程POSIX線程(Pthreads)的頭文件是
一、線程的概念一般來說,我們把正在計算機中執(zhí)行的程序叫做進程(Process) ,而不將其稱為程序(Program)。 所謂線程(Thread),是進程中某個單一順序的控制流。 新興的操作系統(tǒng),如Mac,Windows NT,Windows 95等,大多采用多線程的概念,把線程視為基本執(zhí)行單位。 線程也是Java中的相當重要的組成部分之一。 甚至最簡單的Applet也是由多個線程來完成的。 在Java中,任何一個Applet的paint()和update()方法都是由AWT(Abstract Window Toolkit)繪圖與事件處理線程調(diào)用的,而Applet 主要的里程碑方法——init(),start(),stop()和destory()——是由執(zhí)行該Applet的應(yīng)用調(diào)用的。 單線程的概念沒有什么新的地方,真正有趣的是在一個程序中同時使用多個線程來完成不同的任務(wù)。 某些地方用輕量進程(Lightweig ht Process)來代替線程,線程與真正進程的相似性在于它們都是單一順序控制流。 然而線程被認為輕量是由于它運行于整個程序的上下文內(nèi),能使用整個程序共有的資源和程序環(huán)境。 作為單一順序控制流,在運行的程序內(nèi)線程必須擁有一些資源作為必要的開銷。 例如,必須有執(zhí)行堆棧和程序計數(shù)器。 在線程內(nèi)執(zhí)行的代碼只在它的上下文中起作用,因此某些地方用執(zhí)行上下文來代替線程。 二、線程屬性為了正確有效地使用線程,必須理解線程的各個方面并了解Java 實時系統(tǒng)。 必須知道如何提供線程體、線程的生命周期、實時系統(tǒng)如 何調(diào)度線程、線程組、什么是幽靈線程(Demo nThread)。 (1)線程體所有的操作都發(fā)生在線程體中,在Java中線程體是從Thread類繼承的run()方法,或?qū)崿F(xiàn)Runnable接口的類中的run()方法。 當線程產(chǎn)生并初始化后,實時系統(tǒng)調(diào)用它的run()方法。 run()方法內(nèi)的代碼實現(xiàn)所產(chǎn)生線程的行為,它是線程的主要部分。 (2)線程狀態(tài)附圖表示了線程在它的生命周期內(nèi)的任何時刻所能處的狀態(tài)以及引起狀態(tài)改變的方法。 這圖并不是完整的有限狀態(tài)圖,但基本概括了線程中比較感興趣和普遍的方面。 以下討論有關(guān)線程生命周期以此為據(jù)。 ●新線程態(tài)(New Thread)產(chǎn)生一個Thread對象就生成一個新線程。 當線程處于新線程狀態(tài)時,僅僅是一個空線程對象,它還沒有分配到系統(tǒng)資源。 因此只能啟動或終止它。 任何其他操作都會引發(fā)異常。 ●可運行態(tài)(Runnable)start()方法產(chǎn)生運行線程所必須的資源,調(diào)度線程執(zhí)行,并且調(diào)用線程的run()方法。 在這時線程處于可運行態(tài)。 該狀態(tài)不稱為運行態(tài)是因為這時的線程并不總是一直占用處理機。 特別是對于只有一個處理機的PC而言,任何時刻只能有一個處于可運行態(tài)的線程占用處理 機。 Java通過調(diào)度來實現(xiàn)多線程對處理機的共享。 ●非運行態(tài)(Not Runnable)當以下事件發(fā)生時,線程進入非運行態(tài)。 ①suspend()方法被調(diào)用;②sleep()方法被調(diào)用;③線程使用wait()來等待條件變量;④線程處于I/O等待。 ●死亡態(tài)(Dead)當run()方法返回,或別的線程調(diào)用stop()方法,線程進入死亡態(tài) 。 通常Applet使用它的stop()方法來終止它產(chǎn)生的所有線程。 (3)線程優(yōu)先級雖然我們說線程是并發(fā)運行的。 然而事實常常并非如此。 正如前面談到的,當系統(tǒng)中只有一個CPU時,以某種順序在單CPU情況下執(zhí)行多線程被稱為調(diào)度(scheduling)。 Java采用的是一種簡單、固定的調(diào)度法,即固定優(yōu)先級調(diào)度。 這種算法是根據(jù)處于可運行態(tài)線程的相對優(yōu)先級來實行調(diào)度。 當線程產(chǎn)生時,它繼承原線程的優(yōu)先級。 在需要時可對優(yōu)先級進行修改。 在任何時刻,如果有多條線程等待運行,系統(tǒng)選擇優(yōu)先級最高的可運行線程運行。 只有當它停止、自動放棄、或由于某種原因成為非運行態(tài)低優(yōu)先級的線程才能運行。 如果兩個線程具有相同的優(yōu)先級,它們將被交替地運行。 Java實時系統(tǒng)的線程調(diào)度算法還是強制性的,在任何時刻,如果一個比其他線程優(yōu)先級都高的線程的狀態(tài)變?yōu)榭蛇\行態(tài),實時系統(tǒng)將選擇該線程來運行。 (4)幽靈線程任何一個Java線程都能成為幽靈線程。 它是作為運行于同一個進程內(nèi)的對象和線程的服務(wù)提供者。 例如,HotJava瀏覽器有一個稱為 后臺圖片閱讀器的幽靈線程,它為需要圖片的對象和線程從文件系統(tǒng)或網(wǎng)絡(luò)讀入圖片。 幽靈線程是應(yīng)用中典型的獨立線程。 它為同一應(yīng)用中的其他對象和線程提供服務(wù)。 幽靈線程的run()方法一般都是無限循環(huán),等待服務(wù)請求。 (5)線程組每個Java線程都是某個線程組的成員。 線程組提供一種機制,使得多個線程集于一個對象內(nèi),能對它們實行整體操作。 譬如,你能用一個方法調(diào)用來啟動或掛起組內(nèi)的所有線程。 Java線程組由ThreadGroup類實現(xiàn)。 當線程產(chǎn)生時,可以指定線程組或由實時系統(tǒng)將其放入某個缺省的線程組內(nèi)。 線程只能屬于一個線程組,并且當線程產(chǎn)生后不能改變它所屬的線程組。 三、多線程程序?qū)τ诙嗑€程的好處這就不多說了。 但是,它同樣也帶來了某些新的麻煩。 只要在設(shè)計程序時特別小心留意,克服這些麻煩并不算太困難。 (1)同步線程許多線程在執(zhí)行中必須考慮與其他線程之間共享數(shù)據(jù)或協(xié)調(diào)執(zhí)行狀態(tài)。 這就需要同步機制。 在Java中每個對象都有一把鎖與之對應(yīng)。 但Java不提供單獨的lock和unlock操作。 它由高層的結(jié)構(gòu)隱式實現(xiàn), 來保證操作的對應(yīng)。 (然而,我們注意到Java虛擬機提供單獨的monito renter和monitorexit指令來實現(xiàn)lock和unlock操作。 )synchronized語句計算一個對象引用,試圖對該對象完成鎖操作, 并且在完成鎖操作前停止處理。 當鎖操作完成synchronized語句體得到執(zhí)行。 當語句體執(zhí)行完畢(無論正常或異常),解鎖操作自動完成。 作為面向?qū)ο蟮恼Z言,synchronized經(jīng)常與方法連用。 一種比較好的辦法是,如果某個變量由一個線程賦值并由別的線程引用或賦值,那么所有對該變量的訪問都必須在某個synchromized語句或synchronized方法內(nèi)。 現(xiàn)在假設(shè)一種情況:線程1與線程2都要訪問某個數(shù)據(jù)區(qū),并且要求線程1的訪問先于線程2, 則這時僅用synchronized是不能解決問題的。 這在Unix或Windows NT中可用Simaphore來實現(xiàn)。 而Java并不提供。 在Java中提供的是wait()和notify()機制。 使用如下:synchronized method-1(…){ call by thread 1.‖access data area;available=true;notify()}synchronized method-2(…){‖call by thread (!available)try{wait();‖wait for notify().}catch (Interrupted Exception e){}‖access data area}其中available是類成員變量,置初值為false。 如果在method-2中檢查available為假,則調(diào)用wait()。 wait()的作用是使線程2進入非運行態(tài),并且解鎖。 在這種情況下,method-1可以被線程1調(diào)用。 當執(zhí)行notify()后。 線程2由非運行態(tài)轉(zhuǎn)變?yōu)榭蛇\行態(tài)。 當method-1調(diào)用返回后。 線程2可重新對該對象加鎖,加鎖成功后執(zhí)行wait()返回后的指令。 這種機制也能適用于其他更復(fù)雜的情況。 (2)死鎖如果程序中有幾個競爭資源的并發(fā)線程,那么保證均衡是很重要的。 系統(tǒng)均衡是指每個線程在執(zhí)行過程中都能充分訪問有限的資源。 系統(tǒng)中沒有餓死和死鎖的線程。 Java并不提供對死鎖的檢測機制。 對大多數(shù)的Java程序員來說防止死鎖是一種較好的選擇。 最簡單的防止死鎖的方法是對競爭的資源引入序號,如果一個線程需要幾個資源,那么它必須先得到小序號的資源,再申請大序號的資源。 四、線程和進程的比較進程是資源分配的基本單位。 所有與該進程有關(guān)的資源,都被記錄在進程控制塊PCB中。 以表示該進程擁有這些資源或正在使用它們。 另外,進程也是搶占處理機的調(diào)度單位,它擁有一個完整的虛擬地址空間。 與進程相對應(yīng),線程與資源分配無關(guān),它屬于某一個進程,并與進程內(nèi)的其他線程一起共享進程的資源。 當進程發(fā)生調(diào)度時,不同的進程擁有不同的虛擬地址空間,而同一進程內(nèi)的不同線程共享同一地址空間。 線程只由相關(guān)堆棧(系統(tǒng)棧或用戶棧)寄存器和線程控制表TCB組成。 寄存器可被用來存儲線程內(nèi)的局部變量,但不能存儲其他線程的相關(guān)變量。 發(fā)生進程切換與發(fā)生線程切換時相比較,進程切換時涉及到有關(guān)資源指針的保存以及地址空間的變化等問題;線程切換時,由于同不進程內(nèi)的線程共享資源和地址 空間,將不涉及資源信息的保存和地址變化問題,從而減少了操作系統(tǒng)的開銷時間。 而且,進程的調(diào)度與切換都是由操作系統(tǒng)內(nèi)核完成,而線程則既可由操作系統(tǒng)內(nèi) 核完成,也可由用戶程序進行。 五、線程的適用范圍典型的應(yīng)用 1.服務(wù)器中的文件管理或通信控制 2.前后臺處理 3.異步處理六、線程的執(zhí)行特性一個線程必須處于如下四種可能的狀態(tài)之一:初始態(tài):一個線程調(diào)用了new方法之后,并在調(diào)用start方法之前的所處狀態(tài)。 在初始態(tài)中,可以調(diào)用start和stop方法。 Runnable:一旦線程調(diào)用了start 方法,線程就轉(zhuǎn)到Runnable 狀態(tài),注意,如果線程處于Runnable狀態(tài),它也有可能不在運行,這是因為還有優(yōu)先級和調(diào)度問題。 阻塞/ NonRunnable:線程處于阻塞/NonRunnable狀態(tài),這是由兩種可能性造成的:要么是因掛起而暫停的,要么是由于某些原因而阻塞的,例如包括等待IO請求的完成。 退出:線程轉(zhuǎn)到退出狀態(tài),這有兩種可能性,要么是run方法執(zhí)行結(jié)束,要么是調(diào)用了stop方法。 最后一個概念就是線程的優(yōu)先級,線程可以設(shè)定優(yōu)先級,高優(yōu)先級的線程可以安排在低優(yōu)先級線程之前完成。 一個應(yīng)用程序可以通過使用線程中的方法setPriority(int),來設(shè)置線程的優(yōu)先級大小。 線程有5種基本操作: 派生:線程在進程內(nèi)派生出來,它即可由進程派生,也可由線程派生。 阻塞(Block):如果一個線程在執(zhí)行過程中需要等待某個事件發(fā)生,則被阻塞。 激活(unblock):如果阻塞線程的事件發(fā)生,則該線程被激活并進入就緒隊列。 調(diào)度(schedule):選擇一個就緒線程進入執(zhí)行狀態(tài)。 結(jié)束(Finish):如果一個線程執(zhí)行結(jié)束,它的寄存器上下文以及堆棧內(nèi)容等將被釋放。 七、線程的分類線程有兩個基本類型: 用戶級線程:管理過程全部由用戶程序完成,操作系統(tǒng)內(nèi)核心只對進程進行管理。 系統(tǒng)級線程(核心級線程):由操作系統(tǒng)內(nèi)核進行管理。 操作系統(tǒng)內(nèi)核給應(yīng)用程序提供相應(yīng)的系統(tǒng)調(diào)用和應(yīng)用程序接口API,以使用戶程序可以創(chuàng)建、執(zhí)行、撤消線程。 附:線程舉例1. SUN Solaris 2.3Solaris支持內(nèi)核線程、輕權(quán)進程和用戶線程。 一個進程可有大量用戶線程;大量用戶線程復(fù)用少量的輕權(quán)進程,輕權(quán)進程與內(nèi)核線程一一對應(yīng)。 用戶級線程在調(diào)用核心服務(wù)時(如文件讀寫),需要“捆綁(bound)”在一個LWP上。 永久捆綁(一個LWP固定被一個用戶級線程占用,該LWP移到LWP池之外)和臨時捆綁(從LWP池中臨時分配一個未被占用的LWP)。 在調(diào)用系統(tǒng)服務(wù)時,如果所有LWP已被其他用戶級線程所占用(捆綁),則該線程阻塞直到有可用的LWP。 如果LWP執(zhí)行系統(tǒng)線程時阻塞(如read()調(diào)用),則當前捆綁在LWP上的用戶級線程也阻塞。 ¨有關(guān)的C庫函數(shù)/* 創(chuàng)建用戶級線程 */int thr_create(void *stack_base, size_t stack_size,void *(*start_routine)(void *), void *arg, long flags,thread_t *new_thread_id);其中flags包括:THR_BOUND(永久捆綁), THR_NEW_LWP(創(chuàng)建新LWP放入LWP池),若兩者同時指定則創(chuàng)建兩個新LWP,一個永久捆綁而另一個放入LWP池。 2有關(guān)的系統(tǒng)調(diào)用 /* 在當前進程中創(chuàng)建LWP */int _lwp_create(ucontext_t *contextp, unsigned long flags,lwpid_t *new_lwp_id);/* 構(gòu)造LWP上下文*/void _lwp_makecontext(ucontext_t *ucp, void (*start_routine)( void *), void *arg,void *private, caddr_t stack_base, size_t stack_size);/* 注意:沒有進行“捆綁”操作的系統(tǒng)調(diào)用 */2. Windows NTNT線程的上下文包括:寄存器、核心棧、線程環(huán)境塊和用戶棧。 NT線程狀態(tài) (1) 就緒狀態(tài):進程已獲得除處理機外的所需資源,等待執(zhí)行。 (2) 備用狀態(tài):特定處理器的執(zhí)行對象,系統(tǒng)中每個處理器上只能有一個處于備用狀態(tài)的線程。 (3) 運行狀態(tài):完成描述表切換,線程進入運行狀態(tài),直到內(nèi)核搶先、時間片用完、線程終止或進行等待狀態(tài)。 (4) 等待狀態(tài):線程等待對象句柄,以同步它的執(zhí)行。 等待結(jié)束時,根據(jù)優(yōu)先級進入運行、就緒狀態(tài)。 (5) 轉(zhuǎn)換狀態(tài):線程在準備執(zhí)行而其內(nèi)核堆棧處于外存時,線程進入轉(zhuǎn)換狀態(tài);當其內(nèi)核堆棧調(diào)回內(nèi)存,線程進入就緒狀態(tài)。 (6) 終止狀態(tài):線程執(zhí)行完就進入終止狀態(tài);如執(zhí)行體有一指向線程對象的指針,可將線程對象重新初始化,并再次使用。 NT線程的有關(guān)APICreateThread()函數(shù)在調(diào)用進程的地址空間上創(chuàng)建一個線程,以執(zhí)行指定的函數(shù);返回值為所創(chuàng)建線程的句柄。 ExitThread()函數(shù)用于結(jié)束本線程。 SuspendThread()函數(shù)用于掛起指定的線程。 ResumeThread()函數(shù)遞減指定線程的掛起計數(shù),掛起計數(shù)為0時,線程恢復(fù)執(zhí)行。
內(nèi)容聲明:
1、本站收錄的內(nèi)容來源于大數(shù)據(jù)收集,版權(quán)歸原網(wǎng)站所有!
2、本站收錄的內(nèi)容若侵害到您的利益,請聯(lián)系我們進行刪除處理!
3、本站不接受違法信息,如您發(fā)現(xiàn)違法內(nèi)容,請聯(lián)系我們進行舉報處理!
4、本文地址:http://www.hudongshop.com/article/b13e50c6f448876b4db8.html,復(fù)制請保留版權(quán)鏈接!
簡介多項式擬合是一種機器學習技術(shù),用于擬合數(shù)據(jù)點到多項式曲線,它是一種強大的工具,可以用于各種應(yīng)用,包括回歸分析、曲線擬合和預(yù)測,在本文中,我們將探討多項式擬合在機器學習和人工智能中的應(yīng)用,我們將從理論基礎(chǔ)開始,然后討論實際應(yīng)用以及使用多項式擬合的代碼示例,理論基礎(chǔ)多項式擬合的目標是找到一個多項式函數(shù),它最能擬合一組數(shù)據(jù)點,對于給定的...。
本站公告 2024-09-29 19:16:44
隨著企業(yè)數(shù)據(jù)不斷增長,管理和優(yōu)化存儲空間變得越來越具有挑戰(zhàn)性,磁盤配額是一種有用的工具,可以通過自動化存儲管理流程,為管理員節(jié)省大量時間和精力,什么是磁盤配額,磁盤配額是指為指定用戶或組分配的存儲空間限制,通過實施磁盤配額,管理員可以限制特定用戶或組可以使用的存儲量,這有助于防止單個用戶或組壟斷共享存儲池,并確保所有用戶公平地訪問存儲...。
技術(shù)教程 2024-09-25 12:06:29
DelphiXE5是一款用于構(gòu)建桌面、移動和網(wǎng)絡(luò)應(yīng)用程序的強大開發(fā)工具,它提供了豐富的功能和特性,使開發(fā)人員能夠創(chuàng)建高性能、可擴展且易于維護的應(yīng)用程序,桌面應(yīng)用程序DelphiXE5非常適合構(gòu)建功能豐富且用戶友好的桌面應(yīng)用程序,它支持各種控件和組件,包括按鈕、文本框、網(wǎng)格和圖表,開發(fā)人員可以使用直觀的拖放界面輕松地創(chuàng)建復(fù)雜的應(yīng)用程序,...。
互聯(lián)網(wǎng)資訊 2024-09-24 09:53:13
前言在現(xiàn)代web開發(fā)中,多媒體內(nèi)容扮演著越來越重要的角色,從視頻和音頻到交互式3D模型,豐富的多媒體體驗可以顯著提升用戶參與度和網(wǎng)站整體質(zhì)量,為了在網(wǎng)頁上實現(xiàn)這些多媒體內(nèi)容,網(wǎng)頁播放器發(fā)揮著至關(guān)重要的作用,網(wǎng)頁播放器是一個包含用戶界面和媒體播放功能的嵌入式組件,允許用戶輕松控制和觀看媒體內(nèi)容,常見的網(wǎng)頁播放器技術(shù)HTML5媒體元素HT...。
技術(shù)教程 2024-09-15 17:17:18
簡介fprintf函數(shù)是C編程語言中用于格式化輸出的強大工具,它允許您以一種可控的方式將數(shù)據(jù)寫入文件或標準輸出流,通過使用格式化字符串,您可以指定輸出數(shù)據(jù)的特定格式,例如對齊、寬度和精度,語法fprintf函數(shù)的語法如下,```cintfprintf,F(xiàn)ILEstream,constcharformat,...,```其中,`str...。
互聯(lián)網(wǎng)資訊 2024-09-15 11:20:39
掌握數(shù)據(jù)庫三范式,創(chuàng)建高效且可靠的數(shù)據(jù)庫、靈活性和安全性,雖然可能會有一些注意事項,但三范式仍然是設(shè)計健壯和可靠的關(guān)系數(shù)據(jù)庫的基礎(chǔ),...。
本站公告 2024-09-13 10:29:40
作為一名PHP開發(fā)者,實現(xiàn)編寫干凈、可維護且高效的代碼至關(guān)重要,這不僅可以提高你的生產(chǎn)力,還可以幫助你構(gòu)建更健壯、更可靠的應(yīng)用程序,本文將介紹一些PHP最佳實踐,幫助你提高代碼質(zhì)量,這些實踐涵蓋了編碼風格、錯誤處理、性能優(yōu)化和安全性等各個方面,編碼風格保持一致的編碼風格對于提高代碼可讀性和可維護性至關(guān)重要,以下是一些編碼風格最佳實踐,...。
互聯(lián)網(wǎng)資訊 2024-09-12 14:39:38
數(shù)據(jù)存儲優(yōu)化對于提高應(yīng)用程序性能和降低成本至關(guān)重要,通過優(yōu)化數(shù)據(jù)存儲,可以減少應(yīng)用程序的響應(yīng)時間、提高吞吐量并降低存儲成本,數(shù)據(jù)存儲優(yōu)化包括,選擇正確的存儲類型,根據(jù)應(yīng)用程序的工作負載和性能要求,選擇適當?shù)拇鎯︻愋停鐗K存儲、文件存儲或?qū)ο蟠鎯Γ瑑?yōu)化數(shù)據(jù)結(jié)構(gòu),設(shè)計數(shù)據(jù)結(jié)構(gòu)以減少冗余和提高查詢性能,例如使用索引和表分區(qū),實現(xiàn)緩存,將常...。
互聯(lián)網(wǎng)資訊 2024-09-11 13:20:22
引言Flash,一種曾經(jīng)無所不在的交互式多媒體平臺,近年來已被HTML5等更新技術(shù)所超越,F(xiàn)lash源碼仍然是為網(wǎng)站和應(yīng)用程序創(chuàng)建引人注目的交互性和視覺效果的寶貴工具,本指南將為您提供掌握Flash源碼所需的知識和技能,從而提升您的網(wǎng)站和應(yīng)用程序,我們將探討Flash源碼的基礎(chǔ)知識、各種工具,以及創(chuàng)建令人驚嘆的交互式體驗的最佳實踐,什...。
本站公告 2024-09-10 14:54:19
隨著云計算的蓬勃發(fā)展,越來越多的企業(yè)和個人選擇基于云的解決方案來滿足他們的計算和存儲需求,與傳統(tǒng)的本地軟件相比,基于云的解決方案提供了許多優(yōu)勢,其中一個主要優(yōu)勢就是無需本地安裝或維護,這帶來的好處包括,降低成本,無需購買和維護本地硬件,從而降低了前期成本和持續(xù)成本,提高可擴展性,云平臺可以輕松地按需縱向擴展或縮小,以適應(yīng)業(yè)務(wù)需求的變化...。
互聯(lián)網(wǎng)資訊 2024-09-09 18:01:21
結(jié)賬是購買過程中的關(guān)鍵一步,也是許多企業(yè)面臨的挑戰(zhàn),復(fù)雜且耗時的結(jié)賬流程可能會讓客戶望而卻步,導致銷售損失,為了避免這種情況,企業(yè)可以采取多種措施來簡化結(jié)賬流程,提高客戶滿意度,在本文中,我們將探討結(jié)賬后才能進行的常見操作以及這些操作如何影響客戶體驗,我們還將提供一些提示,幫助企業(yè)簡化結(jié)賬流程,結(jié)賬后才能進行的常見操作以下是一些常見的...。
互聯(lián)網(wǎng)資訊 2024-09-06 08:40:24
由于現(xiàn)在網(wǎng)站建設(shè)的門檻是比較低的,做網(wǎng)站變得非常容易,小企業(yè)甚至個人都可以利用各種自助網(wǎng)站建設(shè)系統(tǒng)來建設(shè)自己的網(wǎng)站,擁有自己的網(wǎng)站,便于宣傳、展示企業(yè)形象、推廣產(chǎn)品和品牌營銷,那么自己如何做網(wǎng)站,步驟是什么,其實很簡單,只要做以下步驟,一、下載自助建站系統(tǒng)目前市場上自助建站系統(tǒng)很多,但是并不是說所有的質(zhì)量都是好的,我們需要仔細的進行辨...。
技術(shù)教程 2024-09-02 02:33:49