<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    java線程池的應(yīng)用

    Posted on 2010-10-14 13:10 myfavorite 閱讀(2352) 評(píng)論(0)  編輯  收藏
            一直是在NET的平臺(tái)做應(yīng)用軟件的開發(fā)的,在上一個(gè)項(xiàng)目完成后,公司定下新的項(xiàng)目改為在java平臺(tái)開發(fā),說是行業(yè)要求。這可是要了我的命。我對(duì)java可是一點(diǎn)都不了解,更搞不懂這java,jsp等等這些的差別,突然要搞這個(gè),而且項(xiàng)目還緊,郁悶死。都有想要離職的念頭。可是總在猶豫不決中,遲遲下不了決心...... 

            不管別的,只要在公司呆著,就得干活。公司可不會(huì)養(yǎng)什么閑人。
            先就當(dāng)學(xué)習(xí)吧。安裝java的開發(fā)環(huán)境:jdk,開發(fā)工具:MyEclipse,在趕項(xiàng)目的同事開始Java的學(xué)習(xí)。

           第一個(gè)任務(wù)是編寫一個(gè)java的后臺(tái)服務(wù),主要處理是解析報(bào)文數(shù)據(jù)。在NET的開發(fā)工具下,可以直接建立一個(gè)Windows Service項(xiàng)目。在網(wǎng)上搜索了下,java的平臺(tái)下,都是將java的應(yīng)用轉(zhuǎn)為Windows Service,這就用了半天的時(shí)間,郁悶死。趕的急,先就寫java應(yīng)用吧。首先連接數(shù)據(jù)庫(kù),下載相關(guān)包文件,配置連接,搜索相關(guān)的代碼,抄過來后修改先關(guān)連接參數(shù)后運(yùn)行,結(jié)果不是Connect Refused,就是Error establishing socket,又郁悶的要死。看網(wǎng)上說的可能是數(shù)據(jù)庫(kù)安裝的問題,但是又不想重新安裝數(shù)據(jù)庫(kù),實(shí)在沒有招了,試著連別人的數(shù)據(jù)庫(kù),奇怪這就可以連接了!查了下數(shù)據(jù)庫(kù)的區(qū)別,正常連接的數(shù)據(jù)庫(kù)版本是Enterprise Evaluation Edition,本地?cái)?shù)據(jù)庫(kù)版本是Developer Edition。可能是這個(gè)原因吧。反正搞的很郁悶,這又用了近半天的時(shí)間。在寫應(yīng)用的過程中,使用到substring函數(shù),又要抓狂了。java下的這個(gè)函數(shù)的參數(shù)和其他語言下該函數(shù)的參數(shù)有差別,剛開始沒注意,執(zhí)行時(shí)總是結(jié)果不對(duì)。搞了半天才發(fā)現(xiàn)這個(gè)問題。

             哎,慢慢做吧。今天要用到線程池的應(yīng)用,在網(wǎng)上看到一段不錯(cuò)的代碼,抄錄過來學(xué)習(xí)下。

             所謂線程池,即在進(jìn)程啟動(dòng)時(shí),同時(shí)生成一定數(shù)量的線程,把他們放入一個(gè)容器中,這樣,當(dāng)有需求時(shí),從池中取出一個(gè)線程去處理請(qǐng)求,當(dāng)池里的線程用完時(shí),在有請(qǐng)求時(shí)則只能等待。 

            下面是一個(gè)簡(jiǎn)單的java例子,來示范java中線程池的應(yīng)用。

            示例程序由三個(gè)類構(gòu)成,主要實(shí)現(xiàn)一下功能:每輸入一行字符串,就請(qǐng)求一個(gè)線程去模擬處理
            第一個(gè)是TestThreadPool類,它是一個(gè)測(cè)試程序,用來模擬客戶端的請(qǐng)求,當(dāng)你運(yùn)行它時(shí),系統(tǒng)首先會(huì)顯示線程池的初始化信息,然后提示你從鍵盤上輸入字符串,并按下回車鍵,這時(shí)你會(huì)發(fā)現(xiàn)屏幕上顯示信息,告訴你某個(gè)線程正在處理你的請(qǐng)求,如果你快速地輸入一行行字符串,那么你會(huì)發(fā)現(xiàn)線程池中不斷有線程被喚醒,來處理你的請(qǐng)求,在本例中,我創(chuàng)建了一個(gè)擁有10個(gè)線程的線程池,如果線程池中沒有可用線程了,系統(tǒng)會(huì)提示你相應(yīng)的警告信息,但如果你稍等片刻,那你會(huì)發(fā)現(xiàn)屏幕上會(huì)陸陸續(xù)續(xù)提示有線程進(jìn)入了睡眠狀態(tài),這時(shí)你又可以發(fā)送新的請(qǐng)求了。

            第二個(gè)類是ThreadPoolManager類,顧名思義,它是一個(gè)用于管理線程池的類,它的主要職責(zé)是初始化線程池,并為客戶端的請(qǐng)求分配不同的線程來進(jìn)行處理,如果線程池滿了,它會(huì)對(duì)你發(fā)出警告信息。

            最后一個(gè)類是SimpleThread類,它是Thread類的一個(gè)子類,它才真正對(duì)客戶端的請(qǐng)求進(jìn)行處理,SimpleThread在示例程序初始化時(shí)都處于睡眠狀態(tài),但如果它接受到了ThreadPoolManager類發(fā)過來的調(diào)度信息,則會(huì)將自己?jiǎn)拘眩?duì)請(qǐng)求進(jìn)行處理。
      
            首先我們來看一下TestThreadPool類的源碼:
    // TestThreadPool.java
    import java.io.*;

    public class TestThreadPool {
        
    public static void main(String[] args) {
            
    try {
                BufferedReader br 
    = new BufferedReader(new InputStreamReader(
                        System.in));
                String s;
                ThreadPoolManager manager 
    = new ThreadPoolManager(10);
                
    while ((s = br.readLine()) != null{
                    manager.process(s);
                }

            }
     catch (IOException e) {
            }

        }

    }

            由于此測(cè)試程序用到了輸入輸入類,因此第1行導(dǎo)入了JAVA的基本IO處理包,在第11行中,我們創(chuàng)建了一個(gè)名為manager的類,它給ThreadPoolManager類的構(gòu)造函數(shù)傳遞了一個(gè)值為10的參數(shù),告訴ThreadPoolManager類:我要一個(gè)有10個(gè)線程的池,給我創(chuàng)建一個(gè)吧!第12行至15行是一個(gè)無限循環(huán),它用來等待用戶的鍵入,并將鍵入的字符串保存在s變量中,并調(diào)用ThreadPoolManager類的process方法來將這個(gè)請(qǐng)求進(jìn)行處理。

            下面我們?cè)龠M(jìn)一步跟蹤到ThreadPoolManager類中去,以下是它的源代碼:
    //ThreadPoolManager.java 
    import java.util.*;

    class ThreadPoolManager {

        
    private int maxThread;
        
    public Vector vector;

        
    public void setMaxThread(int threadCount) {
            maxThread 
    = threadCount;
        }


        
    public ThreadPoolManager(int threadCount) {
            setMaxThread(threadCount);
            System.out.println(
    "Starting thread pool");
            vector 
    = new Vector();
            
    for (int i = 1; i <= 10; i++{
                SimpleThread thread 
    = new SimpleThread(i);
                vector.addElement(thread);
                thread.start();
            }

        }


        
    public void process(String argument) {
            
    int i;
            
    for (i = 0; i < vector.size(); i++{
                SimpleThread currentThread 
    = (SimpleThread) vector.elementAt(i);
                
    if (!currentThread.isRunning()) {
                    System.out.println(
    "Thread " + (i + 1+ " is processing:"
                            
    + argument);
                    currentThread.setArgument(argument);
                    currentThread.setRunning(
    true);
                    
    return;
                }

            }

            
    if (i == vector.size()) {
                System.out.println(
    "pool is full, try in another time.");
            }

        }

    }
    // end of class ThreadPoolManager

            我們先關(guān)注一下這個(gè)類的構(gòu)造函數(shù),然后再看它的process()方法。第16-24行是它的構(gòu)造函數(shù),首先它給ThreadPoolManager類的成員變量maxThread賦值,maxThread表示用于控制線程池中最大線程的數(shù)量。第18行初始化一個(gè)數(shù)組vector,它用來存放所有的SimpleThread類,這時(shí)候就充分體現(xiàn)了JAVA語言的優(yōu)越性與藝術(shù)性:如果你用C語言的話,至少要寫100行以上的代碼來完成vector的功能,而且C語言數(shù)組只能容納類型統(tǒng)一的基本數(shù)據(jù)類型,無法容納對(duì)象。好了,閑話少說,第19-24行的循環(huán)完成這樣一個(gè)功能:先創(chuàng)建一個(gè)新的SimpleThread類,然后將它放入vector中去,最后用thread.start()來啟動(dòng)這個(gè)線程,為什么要用start()方法來啟動(dòng)線程呢?因?yàn)檫@是JAVA語言中所規(guī)定的,如果你不用的話,那這些線程將永遠(yuǎn)得不到激活,從而導(dǎo)致本示例程序根本無法運(yùn)行。
      
            下面我們?cè)賮砜匆幌聀rocess()方法,第30-40行的循環(huán)依次從vector數(shù)組中選取SimpleThread線程,并檢查它是否處于激活狀態(tài)(所謂激活狀態(tài)是指此線程是否正在處理客戶端的請(qǐng)求),如果處于激活狀態(tài)的話,那繼續(xù)查找vector數(shù)組的下一項(xiàng),如果vector數(shù)組中所有的線程都處于激活狀態(tài)的話,那它會(huì)打印出一條信息,提示用戶稍候再試。相反如果找到了一個(gè)睡眠線程的話,那第35-38行會(huì)對(duì)此進(jìn)行處理,它先告訴客戶端是哪一個(gè)線程來處理這個(gè)請(qǐng)求,然后將客戶端的請(qǐng)求,即字符串a(chǎn)rgument轉(zhuǎn)發(fā)給SimpleThread類的setArgument()方法進(jìn)行處理,并調(diào)用SimpleThread類的setRunning()方法來喚醒當(dāng)前線程,來對(duì)客戶端請(qǐng)求進(jìn)行處理。

      可能你還對(duì)setRunning()方法是怎樣喚醒線程的有些不明白,那我們現(xiàn)在就進(jìn)入最后一個(gè)類:SimpleThread類,它的源代碼如下:

    //SimpleThread.java 
    class SimpleThread extends Thread {
        
    private boolean runningFlag;
        
    private String argument;

        
    public boolean isRunning() {
            
    return runningFlag;
        }


        
    public synchronized void setRunning(boolean flag) {
            runningFlag 
    = flag;
            
    if (flag)
                
    this.notify();
        }


        
    public String getArgument() {
            
    return this.argument;
        }


        
    public void setArgument(String string) {
            argument 
    = string;
        }


        
    public SimpleThread(int threadNumber) {
            runningFlag 
    = false;
            System.out.println(
    "thread " + threadNumber + "started.");
        }


        
    public synchronized void run() {
            
    try {
                
    while (true{
                    
    if (!runningFlag) {
                        
    this.wait();
                    }
     else {
                        System.out.println(
    "processing " + getArgument()
                                
    + " done.");
                        sleep(
    5000);
                        System.out.println(
    "Thread is sleeping");
                        setRunning(
    false);
                    }

                }

            }
     catch (InterruptedException e) {
                System.out.println(
    "Interrupt");
            }

        }
    // end of run()
    }
    // end of class SimpleThread

     

          用戶在run()接口中寫入自己的應(yīng)用處理邏輯。那么怎么來控制線程的睡眠與喚醒呢?其實(shí)很簡(jiǎn)單,JAVA語言為所有的對(duì)象都內(nèi)置了wait()和notify()方法,當(dāng)一個(gè)線程調(diào)用wait()方法時(shí),則線程進(jìn)入睡眠狀態(tài),就像停在了當(dāng)前代碼上了,也不會(huì)繼續(xù)執(zhí)行它以下的代碼了,當(dāng)調(diào)用notify()方法時(shí),則會(huì)從調(diào)用wait()方法的那行代碼繼續(xù)執(zhí)行以下的代碼,這個(gè)過程有點(diǎn)像編譯器中的斷點(diǎn)調(diào)試的概念。以本程序?yàn)槔?8行調(diào)用了wait()方法,則這個(gè)線程就像凝固了一樣停在了38行上了,如果在第13行進(jìn)行一個(gè)notify()調(diào)用的話,那線程會(huì)從第38行上喚醒,繼續(xù)從第39行開始執(zhí)行以下的代碼了。

      通過以上的講述,現(xiàn)在就不難理解SimpleThread類了,第9-14行通過設(shè)置一個(gè)標(biāo)志runningFlag激活當(dāng)前線程,第25-29行是SimpleThread類的構(gòu)造函數(shù),它用來告訴客戶端啟動(dòng)的是第幾號(hào)進(jìn)程。第31-50行則是我實(shí)現(xiàn)的run()接口,它實(shí)際上是一個(gè)無限循環(huán),在循環(huán)中首先判斷一下標(biāo)志runningFlag,如果沒有runningFlag為false的話,那線程處理睡眠狀態(tài),否則第42-45行會(huì)進(jìn)行真正的處理:先打印用戶鍵入的字符串,然后睡眠5秒鐘,為什么要睡眠5秒鐘呢?如果你不加上這句代碼的話,由于計(jì)算機(jī)處理速度遠(yuǎn)遠(yuǎn)超過你的鍵盤輸入速度,因此你看到的總是第1號(hào)線程來處理你的請(qǐng)求,從而達(dá)不到演示效果。最后第45行調(diào)用setRunning()方法又將線程置于睡眠狀態(tài),等待新請(qǐng)求的到來。

      最后還有一點(diǎn)要注意的是,如果在一個(gè)方法中調(diào)用了wait()和notify()函數(shù),那一定要將此方法置為同步的,即synchronized,否則在編譯時(shí)會(huì)報(bào)錯(cuò),并得到一個(gè)莫名其妙的消息:“current thread not owner”(當(dāng)前線程不是擁有者)。


    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国产在线观看免费不卡| 96免费精品视频在线观看| 麻豆69堂免费视频| 久久精品国产亚洲av天美18| 亚洲中文无码永久免| 学生妹亚洲一区二区| 亚洲国产精品无码第一区二区三区| 亚洲日本va在线观看| 亚洲人成色在线观看| 亚洲美国产亚洲AV| 国产精品自拍亚洲| 一级毛片免费不卡直观看| A国产一区二区免费入口| 曰批全过程免费视频在线观看无码 | 国产成人精品日本亚洲专区61| 亚洲日韩人妻第一页| 亚洲日韩精品射精日| 亚洲人成网www| 亚洲国产精品久久丫| 亚洲最大的成人网| 爱爱帝国亚洲一区二区三区| 男人j进女人p免费视频| 亚洲黄片手机免费观看| 久久国产乱子精品免费女| 97在线视频免费公开观看| 9久9久女女免费精品视频在线观看| 成年午夜视频免费观看视频 | 久久免费国产精品一区二区| 1a级毛片免费观看| 日本a级片免费看| 色噜噜AV亚洲色一区二区| 亚洲高清视频在线播放| 亚洲中文字幕无码亚洲成A人片| 国产精品亚洲片在线花蝴蝶| 成人无码视频97免费| 亚洲国产精品无码久久一线| 亚洲国产成人久久精品动漫| 亚洲w码欧洲s码免费| 免费无遮挡无码视频在线观看| 青柠影视在线观看免费高清| 成人免费AA片在线观看|