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

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

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

    和風(fēng)細(xì)雨

    世上本無(wú)難事,心以為難,斯乃真難。茍不存一難之見(jiàn)于心,則運(yùn)用之術(shù)自出。

    #

    線程的死鎖

    本文內(nèi)容

    同步不是改善程序安全性的靈丹妙藥。
    發(fā)生死鎖的兩種情況和解決方法。

    同步不是改善程序安全性的靈丹妙藥

    從《線程的同步》一節(jié)中我們可以知道,synchronized能保證只有一個(gè)線程進(jìn)入同步方法或同步塊,但為了安全性盲目給多線程程序加上synchronized關(guān)鍵字并不是問(wèn)題解決之道,這不但會(huì)降低程序的效率;還有可能帶來(lái)嚴(yán)重的問(wèn)題-死鎖。
    死鎖發(fā)生在兩個(gè)或以上的線程在等待對(duì)象鎖被釋放,但程序的環(huán)境卻讓lock無(wú)法釋放時(shí)。下面我們將看到兩種類(lèi)型的死鎖例子。

    某線程不退出同步函數(shù)造成的死鎖

    public class PaintBoard  extends Thread{
      private boolean flag=true;
     
      public void paint(){   
        System.out.println("模擬繪畫(huà)");
      }
     
      public synchronized void run(){
        while(flag){
          try{
            paint();
            Thread.sleep(1000);
          }
          catch(InterruptedException ex){
            ex.printStackTrace();
          }
        }
      }
     
      public synchronized void stopDraw(){
        flag=false;
        System.out.println("禁止繪畫(huà)");
      }
     
      public static void main(String[] args){
        PaintBoard paintBoard=new PaintBoard();
        paintBoard.start();
        new StopThread(paintBoard);
      }
    }

    public class StopThread implements Runnable{
      private PaintBoard paintBoard;
     
      public StopThread(PaintBoard paintBoard){
        this.paintBoard=paintBoard;
       
        Thread th=new Thread(this);
        th.start();
      }
     
      public void run(){
        while(true){
          System.out.println("試圖停止繪畫(huà)過(guò)程");
          paintBoard.stopDraw();
          System.out.println("停止繪畫(huà)過(guò)程完成");
        }
      }
    }

    問(wèn)題的發(fā)生和解決

    剛才的死鎖原因是run()函數(shù)中有一個(gè)無(wú)限循環(huán),一個(gè)線程進(jìn)入后會(huì)在其中往復(fù)操作,這使它永遠(yuǎn)不會(huì)放棄對(duì)this的鎖定,結(jié)果導(dǎo)致其它線程無(wú)法獲得this的鎖定而進(jìn)入stopDraw函數(shù)。
    我們把修飾run函數(shù)的synchronized取消就能解決問(wèn)題。 run函數(shù)中不會(huì)改變?nèi)魏瘟浚@種函數(shù)是不該加上synchronized的。

    兩個(gè)線程爭(zhēng)搶資源造成的死鎖.

    public class Desk{
      private Object fork=new Object();
      private Object knife=new Object();
     
      public void eatForLeft(){
        synchronized(fork){
          System.out.println("左撇子拿起叉");
          sleep(1);
          synchronized(knife){
            System.out.println("左撇子拿起刀");
            System.out.println("左撇子開(kāi)始吃飯");
          }
        }
      }
     
      public void eatForRight(){
        synchronized(knife){
          System.out.println("右撇子拿起刀");
          sleep(1);
          synchronized(fork){
            System.out.println("右撇子拿起叉");
            System.out.println("右撇子開(kāi)始吃飯");
          }
        }
      }
     
      private void sleep(int second){
        try{
          Thread.sleep(second*1000);
        }
        catch(InterruptedException ex){
          ex.printStackTrace();
        }
      }
     
      public static void main(String[] args){
        Desk desk=new Desk();
        new LeftHand(desk);
        new RightHand(desk);
      }
    }

    public class LeftHand implements Runnable{
      private Desk desk;
     
      public LeftHand(Desk desk){
        this.desk=desk;
       
        Thread th=new Thread(this);
        th.start();
      }
     
      public void run(){
        while(true){
          desk.eatForLeft();
        }
      }
    }

    public class RightHand implements Runnable{
      private Desk desk;
     
      public RightHand(Desk desk){
        this.desk=desk;
       
        Thread th=new Thread(this);
        th.start();
      }
     
      public void run(){
        while(true){
          desk.eatForRight();
        }
      }
    }

    問(wèn)題的發(fā)生和解決

    這部分程序中于兩個(gè)線程都要獲得兩個(gè)對(duì)象的鎖定才能執(zhí)行實(shí)質(zhì)性操作,但運(yùn)行起來(lái)卻發(fā)現(xiàn)其它線程持有了自己需要的另一個(gè)鎖定,于是停在Wait Set中等待對(duì)方釋放這個(gè)鎖定,結(jié)果造成了死鎖。
    解決這個(gè)問(wèn)題的方法是保證鎖對(duì)象的持有順序,如果兩個(gè)加上了同步的函數(shù)都是先刀后叉的形式則不會(huì)發(fā)生問(wèn)題。

    小結(jié)

    同步不是改善程序安全性的靈丹妙藥,盲目同步也會(huì)導(dǎo)致嚴(yán)重的問(wèn)題-死鎖.
    某線程持續(xù)不退出同步函數(shù)會(huì)造成死鎖.解決方法是去掉或更換不正確的同步。
    兩個(gè)線程都等待對(duì)方釋放自己需要的資源也會(huì)造成死鎖.這種情況的解決方法是確保同步鎖對(duì)象的持有順序。

    posted @ 2008-02-22 14:11 和風(fēng)細(xì)雨 閱讀(786) | 評(píng)論 (0)編輯 收藏

    線程的互斥

    多線程操作同一實(shí)例的問(wèn)題

    在多線程環(huán)境中,經(jīng)常有兩個(gè)以上線程操作同一實(shí)例的問(wèn)題,無(wú)論是并行Parallel環(huán)境還是并發(fā)Concurrent環(huán)境,都有發(fā)生有多個(gè)線程修改同一變量的問(wèn)題,如果這個(gè)變量是成員變量,多線程將會(huì)給程序帶來(lái)破壞性的影響。請(qǐng)見(jiàn)以下代碼。

    資源庫(kù)類(lèi)

    public class ResourceLib {
      private long count1;

      private long count2;

      public ResourceLib(int count) {
        this.count1 = count;     
        this.count2 = count;
      }

      /**
       * 取回資源
       * 加上synchronized才是線程安全
       *
       * @param count
       */
      public void fetch(int count) {
        count1 += count;   
        mockLongTimeProcess();   
        count2 += count;   
        checkTwoCount(count);
      }

      /**
       * 送出資源
       * 加上synchronized才是線程安全
       *
       * @param count
       * @return
       */
      public void send(int count) {
        count1 -= count;   
        mockLongTimeProcess();   
        count2 -= count;
        checkTwoCount(count);
      }

       /**
       * 模擬一個(gè)耗時(shí)過(guò)程
       *
       */
      private void mockLongTimeProcess(){
        try{
          Thread.sleep(1000);
        }
        catch(Exception ex){
          ex.printStackTrace();
        }
      }

      private void checkTwoCount(int borrowCount) {
        if (count1 != count2) {
          System.out.println(count1 + "!= " + count2);
          System.exit(0);
        } else {
          System.out.println(count1 + "==" + count2);
        }
       
        if (Math.abs(count1) > 10000000 || Math.abs(count2) > 10000000) {
          count1 = 0;
          count2 = 0;
        }
      }

      public static void main(String[] args) {
        ResourceLib lib = new ResourceLib(10000);

        for (int i = 1; i < 20; i++) {
          new Supplier(String.valueOf(i), i, lib);
        }

        for (int i = 1; i < 10; i++) {
          new Comsumer(String.valueOf(i), i, lib);
        }
      }
    }

    取資源和給資源的兩個(gè)線程

    public class Comsumer implements Runnable{
      private ResourceLib resourceLib;
      private int count;
     
      public Comsumer(String name,int count,ResourceLib resourceLib){
        this.count=count;
        this.resourceLib=resourceLib;
       
        Thread thread=new Thread(this);
        thread.start();
      }
     
      public void run(){
        while(true){
          resourceLib.send(count);
        }
      }
    }

    public class Supplier implements Runnable{
      private ResourceLib resourceLib;
      private int count;
     
      public Supplier(String name,int count,ResourceLib resourceLib){
        this.count=count;
        this.resourceLib=resourceLib;
       
        Thread thread=new Thread(this);
        thread.start();
      }
     
      public void run(){
        while(true){
          resourceLib.fetch(count);
        }
      }
    }

    運(yùn)行結(jié)果

    在main函數(shù)中,程序啟動(dòng)了多個(gè)消費(fèi)者線程和生產(chǎn)者線程,消費(fèi)者線程在不斷減少count1和count2;生產(chǎn)者線程在不斷增加count1和count2,在單線程環(huán)境中,程序絕不會(huì)出現(xiàn)count1和count2不相等的情況,而多線程環(huán)境中,可能有一個(gè)線程在檢查count1和count2時(shí),其中一個(gè)已經(jīng)被另一個(gè)線程所修改。
    因此導(dǎo)致了兩個(gè)值不相等的情況發(fā)生。

    運(yùn)行結(jié)果之一
    10145!= 10001
    10145!= 10003
    10145!= 10006
    10145!= 10010
    10145!= 10015
    10145!= 10021
    10145!= 10028
    10145!= 10036
    10145!= 10045
    10145!= 10055
    10145!= 10066

    另一個(gè)經(jīng)典多線程實(shí)例:銀行取款

    package com.sitinspring.unsafebank;

    public class Bank{
      private int count;
     
      public Bank(int count){
        this.count=count;
      }
     
      public void withdraw(int money){
        if(count>money){
          mockLongTimeProcess();// 模擬耗時(shí)過(guò)程
          count-=money;
          System.out.println("提走"+money+" 現(xiàn)有"+count);    
        }
        else{
          System.out.println(" 現(xiàn)有數(shù)量"+count+"小于"+money+" 不能提取");
        }
       
        checkCount();
      }
     
      public void checkCount(){
        if(count<0){
          System.out.println(count + "< 0 ");
          System.exit(0);
        }
      }

     /**
       * 模擬一個(gè)耗時(shí)過(guò)程
       *
       */
      private void mockLongTimeProcess(){
        try{
          Thread.sleep(1000);
        }
        catch(Exception ex){
          ex.printStackTrace();
        }
      }
     
      public static void main(String[] args){
        Bank bank=new Bank(1000);
       
        for(int i=1;i<10;i++){
          new Customer(i*i*i,bank);
        }
      }
    }

    客戶類(lèi)及講述

    public class Customer implements Runnable{
      private Bank bank;
      private int count;
     
      public Customer(int count,Bank bank){
        this.count=count;
        this.bank=bank;
       
        Thread thread=new Thread(this);
        thread.start();
      }
     
      public void run(){
        while(true){
          bank.withdraw(count);
        }
      }
    }

    在單線程環(huán)境中,提款時(shí)銀行的總數(shù)絕不會(huì)是負(fù)數(shù),但在多線程環(huán)境中,有可能在一個(gè)線程A符合條件在進(jìn)行耗時(shí)運(yùn)算和網(wǎng)絡(luò)數(shù)據(jù)傳遞時(shí),另一個(gè)線程B已經(jīng)把錢(qián)提走,總數(shù)已經(jīng)發(fā)生變化,結(jié)果A線程再提款時(shí)總錢(qián)數(shù)已經(jīng)減小了,因此致使銀行總錢(qián)數(shù)小于零。

    解決方法:在對(duì)成員變量進(jìn)行修改的函數(shù)前加上synchronized關(guān)鍵字

    synchronized方法又被成為”同步“方法。當(dāng)一個(gè)方法加上關(guān)鍵字synchronized聲明之后,就可以讓一個(gè)線程操作這個(gè)方法。“讓一個(gè)線程操作”并不是說(shuō)只能讓某一個(gè)特定的線程操作而已,而是指一次只能讓一個(gè)線程執(zhí)行,也就是說(shuō),在一個(gè)線程沒(méi)有退出同步方法前,其它線程絕無(wú)可能進(jìn)入這個(gè)同步方法和其它并列的同步方法,只能在外面排隊(duì)等候。
    一個(gè)實(shí)例的synchronized方法只能允許1次一個(gè)線程執(zhí)行。但是非synchronized方法就沒(méi)有這個(gè)限制,它可以供2個(gè)以上的線程執(zhí)行。

    修改后的線程安全的Bank類(lèi)

    public class Bank{
      private int count;
     
      public Bank(int count){
        this.count=count;
      }
     
      public synchronized void withdraw(int money){
        if(count>money){
          mockLongTimeProcess();// 模擬耗時(shí)過(guò)程
          count-=money;
          System.out.println("提走"+money+" 現(xiàn)有"+count);    
        }
        else{
          System.out.println(" 現(xiàn)有數(shù)量"+count+"小于"+money+" 不能提取");
        }
       
        checkCount();
      }
     
      public void checkCount(){
        if(count<0){
          System.out.println(count + "< 0 ");
          System.exit(0);
        }
      }
    。。。、// 部分代碼省略
    }



    修改后的線程安全的ResourceLib類(lèi)

    public class ResourceLib {
      private long count1;
      private long count2;

      public synchronized void fetch(int count) {
        count1 += count;   
        mockLongTimeProcess();   
        count2 += count;   
        checkTwoCount(count);
      }

      public synchronized void send(int count) {
        count1 -= count;   
        mockLongTimeProcess();   
        count2 -= count;
        checkTwoCount(count);
      }

      public void checkTwoCount(int borrowCount) {
        if (count1 != count2) {
          System.out.println(count1 + "!= " + count2);
          System.exit(0);
        } else {
          System.out.println(count1 + "==" + count2);
        }
       
        if (Math.abs(count1) > 10000000 || Math.abs(count2) > 10000000) {
          count1 = 0;
          count2 = 0;
        }
      }
    }

    注:部分代碼省略



    執(zhí)行之后

    在一個(gè)執(zhí)行synchronized方法的線程執(zhí)行結(jié)束后,鎖定即被釋放, 其它不得其門(mén)而入的線程開(kāi)始爭(zhēng)搶鎖定,一定會(huì)有一個(gè)線程獲取鎖定,沒(méi)有搶到的線程只好再繼續(xù)等候.
    注意: 非靜態(tài)的synchronized方法鎖定的對(duì)象是實(shí)例,靜態(tài)的synchronized方法鎖定的對(duì)象是類(lèi)對(duì)象。

    同步塊

    以下同步方法可用右邊的同步塊代替:
    public synchronized void fun(){
        ………
    }

    與左邊同步方法對(duì)等的同步塊:
    public void fun(){
       synchronized(this){
         ………
       }
    }

    同步塊和同步方法的比較

    1)同步方法鎖定的類(lèi)的實(shí)例或類(lèi)對(duì)象,同步塊則可以換成任意實(shí)例,靈活性更高。
    2)有時(shí)需要多個(gè)鎖定而不是一個(gè),如函數(shù)A和函數(shù)B需要鎖定1,函數(shù)B和函數(shù)C需要鎖定2,這時(shí)如果使用同步方法無(wú)疑會(huì)鎖定A和C,造成程序效率的降低。這時(shí)最應(yīng)該使用同步塊。

    什么時(shí)候該加同步synchronized

    如果一個(gè)函數(shù)或代碼塊有可能被多個(gè)線程進(jìn)入,而這個(gè)函數(shù)或代碼塊又修改了類(lèi)的成員變量,則這個(gè)這個(gè)函數(shù)或代碼塊就應(yīng)該加上同步synchronized。
    如果一個(gè)函數(shù)或代碼有可能被多個(gè)線程進(jìn)入,而這個(gè)函數(shù)或代碼塊只是讀取類(lèi)的成員變量,則這個(gè)這個(gè)函數(shù)或代碼塊就不該加上同步synchronized。

     

    posted @ 2008-02-22 12:43 和風(fēng)細(xì)雨 閱讀(482) | 評(píng)論 (1)編輯 收藏

    線程的創(chuàng)建

    單線程程序

    一般來(lái)說(shuō),在沒(méi)有線程的幫助下,程序在一個(gè)時(shí)間段只能執(zhí)行一段代碼,其它代碼段只有在等待它完成后才能執(zhí)行。該程序的處理流程從頭到尾只有一條線,這樣的程序我們稱之為單線程程序(Single Thread Program)

    典型的單線程程序:
    public class SingleThreadProgram{
      public static void main(String[] args){
        for(int i=0;i<1000;i++){
          System.out.print("SingleThreadProgram");
        }
      }
    }

    多線程程序

    當(dāng)程序由一個(gè)以上的線程所構(gòu)成時(shí),稱此程序?yàn)槎嗑€程程序(Multithread Program),java從設(shè)計(jì)伊始就把程序的多線程能力列入了考慮范圍。
    典型的多線程程序有:

    1)GUI應(yīng)用程序,我們目前做的Swing桌面程序就屬于此類(lèi)。
    2)較花費(fèi)時(shí)間的I/O處理,一般來(lái)說(shuō),文件和網(wǎng)絡(luò)的輸入/輸出處理比較花費(fèi)時(shí)間,如果在這段無(wú)法進(jìn)行其它處理,則程序性能會(huì)大打折扣,遇到這種情況首先要想到用多線程解決問(wèn)題.
    3)多連接網(wǎng)絡(luò)處理。

    并發(fā)(Concurrent)與并行(Parallel)

    當(dāng)有多個(gè)線程在操作時(shí),如果系統(tǒng)只有一個(gè)CPU,則它根本不可能真正同時(shí)進(jìn)行一個(gè)以上的線程,它只能把CPU運(yùn)行時(shí)間劃分成若干個(gè)時(shí)間段,再將時(shí)間段分配給各個(gè)線程執(zhí)行,在一個(gè)時(shí)間段的線程代碼運(yùn)行時(shí),其它線程處于掛起狀態(tài).這種方式我們稱之為并發(fā)(Concurrent).
    當(dāng)系統(tǒng)有一個(gè)以上CPU時(shí),則線程的操作有可能非并發(fā).當(dāng)一個(gè)CPU執(zhí)行一個(gè)線程時(shí),另一個(gè)CPU可以執(zhí)行另一個(gè)線程,兩個(gè)線程互不搶占CPU資源,可以同時(shí)進(jìn)行,這種方式我們稱之為并行(Parallel)



    多線程在并發(fā)和并行環(huán)境中的不同作用

    在并發(fā)環(huán)境時(shí),多線程不可能真正充分利用CPU,節(jié)約運(yùn)行時(shí)間,它只是以”掛起->執(zhí)行->掛起”的方式以很小的時(shí)間片分別運(yùn)行各個(gè)線程,給用戶以每個(gè)線程都在運(yùn)行的錯(cuò)覺(jué).在這種環(huán)境中,多線程程序真正改善的是系統(tǒng)的響應(yīng)性能和程序的友好性.
    在并行環(huán)境中, 一個(gè)時(shí)刻允許多個(gè)線程運(yùn)行,這時(shí)多線程程序才真正充分利用了多CPU的處理能力, 節(jié)省了整體的運(yùn)行時(shí)間.在這種環(huán)境中,多線程程序能體現(xiàn)出它的四大優(yōu)勢(shì):充分利用CPU,節(jié)省時(shí)間,改善響應(yīng)和增加程序的友好性.

    PS:在多核時(shí)代來(lái)臨后,開(kāi)發(fā)多線程程序的能力更是每個(gè)程序員都該具備的.

    創(chuàng)建多線程程序

    創(chuàng)建多線程程序我們通常有兩種方法:
    1)讓類(lèi)繼承java.lang.Thread,這種方法優(yōu)勢(shì)在于調(diào)用稍微方便,一般用于后臺(tái)批處理程序的場(chǎng)合,但劣勢(shì)是類(lèi)無(wú)法再繼承別的類(lèi)。
    2)讓類(lèi)實(shí)現(xiàn)接口java.lang.Runnable,這種方法調(diào)用時(shí)需要借助Thread的幫助,稍顯麻煩,但優(yōu)勢(shì)在于對(duì)類(lèi)繼承體系沒(méi)有影響,這是使用線程時(shí)最常用的方法。
    兩種方法的線程執(zhí)行部分都在run()函數(shù)中,它們的效率沒(méi)有差別。

    多線程程序創(chuàng)建和啟動(dòng)示例

    創(chuàng)建線程

    // 繼承Thread類(lèi)
    public class Thread1 extends Thread{
      public void run(){
        while(true){
          System.out.println("<Thread1 extends Thread>");
        }
      }
    }

    // 實(shí)現(xiàn)Runnable接口
    public class Thread2 implements Runnable{
      public void run(){
        while(true){
          System.out.println("<Thread2 implements Runnable>");
        }
      }
    }

    啟動(dòng)線程

    public class Main{
      public static void main(String[] args){
        // 啟動(dòng)線程1,Thread1直接繼承自java.lang.Thread類(lèi)
        Thread1 th1=new Thread1();
        th1.start();
       
        // 啟動(dòng)線程2,thread2實(shí)現(xiàn)自java.lang.Runnable接口
        Thread2 thread2=new Thread2();
        Thread th2=new Thread(thread2);
        th2.start();
       
        while(true){
          System.out.println("<Main Thread>");
        }
      }
    }

    概念解析Start和Run

    public void run()
    這個(gè)函數(shù)容納線程啟動(dòng)后執(zhí)行的代碼塊,線程啟動(dòng)起來(lái),run函數(shù)中的代碼會(huì)得到執(zhí)行.

    Thead.start()
    這是啟動(dòng)一個(gè)線程的方法,調(diào)用了這個(gè)方法后,線程才會(huì)得到執(zhí)行.

    取得線程執(zhí)行的結(jié)果

    通過(guò)觀察run函數(shù)的簽名public void run()我們可以發(fā)現(xiàn),它既沒(méi)有輸入?yún)?shù),也沒(méi)有返回值,那如何取得線程的返回值呢?一般來(lái)說(shuō)我們有三種辦法:
    1)讓線程修改公有變量,如某類(lèi)的靜態(tài)公有字段.這種方式古老而危險(xiǎn),最好不要采用.
    2)輪詢線程執(zhí)行結(jié)果,線程執(zhí)行的結(jié)果放在線程類(lèi)的一個(gè)字段中,外界不斷通過(guò)輪詢?nèi)ゲ榭磮?zhí)行結(jié)果.這種方式會(huì)浪費(fèi)很多時(shí)間,結(jié)果也不可靠,不建議采用.
    3)回調(diào)方式,把調(diào)用方的指針通過(guò)線程類(lèi)的構(gòu)造函數(shù)傳入線程類(lèi)的一個(gè)字段中,當(dāng)線程執(zhí)行完取得結(jié)果后再通過(guò)這個(gè)字段反向調(diào)用調(diào)用方的函數(shù).這是取得線程執(zhí)行結(jié)果的最佳解決方案.

    下面請(qǐng)看回調(diào)方式的實(shí)現(xiàn).

    Boss類(lèi)
    這個(gè)類(lèi)用于啟動(dòng)Secretary線程去查找文件, findFile()是啟動(dòng)線程并查找的函數(shù), giveBossResult(String file,String reult)是供Secretary類(lèi)回調(diào)的函數(shù).

    public class Boss{
      private String name;
     
      public Boss(String name){
        this.name=name;
      }
     
      public void giveBossResult(String file,String reult){
        if(reult!=null){
          System.out.println("文件"+file+"序列號(hào)等于:"+reult);
        }
        else{
          System.out.println("無(wú)法找到文件"+file);
        }
      }
     
      public void findFile(){  
        Map<String,String> files=new Hashtable<String,String>();   
        files.put("001", "員工花名冊(cè)");
        files.put("002", "企業(yè)收支");
        files.put("003", "客戶花名錄");
        files.put("004", "對(duì)手狀況分析");
        files.put("005", "當(dāng)月收支");
        files.put("006", "市場(chǎng)份額分析");
        files.put("007", "大連酒店一覽");
        files.put("008", "娛樂(lè)場(chǎng)所名錄");
        files.put("009", "關(guān)系單位聯(lián)系名錄");
       
        Secretary andy=new Secretary("Andy",this,"員工花名冊(cè)",files);
        Thread th1=new Thread(andy);
        th1.start();
       
        Secretary cindy=new Secretary("cindy",this,"上市情況分析",files);
        Thread th2=new Thread(cindy);
        th2.start();
      }
     
      public static void main(String[] args){
        Boss boss=new Boss("Bill");
        boss.findFile();
      }
    }

    Secretary類(lèi)

    這個(gè)類(lèi)是進(jìn)行多線程查找文件的類(lèi),查找的結(jié)果通過(guò)回調(diào)方法告知Boss實(shí)例.
    Boss實(shí)例,查找的文件名,查找的集合都通過(guò)Secretary類(lèi)的構(gòu)造函數(shù)傳進(jìn)來(lái).

    public class Secretary implements Runnable{
      private String name;
      private Boss boss;
      private String file;
      private Map<String,String> files;
     
      public Secretary(String name,Boss boss,String file,Map<String,String> files){
        this.name=name;
        this.boss=boss;
        this.file=file;
        this.files=files;
      }
     
      public void run(){
        for(Map.Entry<String,String> entry:files.entrySet()){
             if(entry.getValue().equals(file)){
               boss.giveBossResult(file,entry.getKey());
               return;
             }
        }
       
        boss.giveBossResult(file,null);
      }
    }

    posted @ 2008-02-22 12:34 和風(fēng)細(xì)雨 閱讀(1968) | 評(píng)論 (1)編輯 收藏

    一個(gè)JMS發(fā)送接受程序示例(Weblogic)

         摘要: 一.Prop類(lèi)(用來(lái)讀取屬性文件,單例) package com.sitinspring.standardWeblogicJms; import java.io.FileInputStream; import java.util.Hashtable; import java.util.Properties; import ja...  閱讀全文

    posted @ 2008-02-22 12:18 和風(fēng)細(xì)雨 閱讀(760) | 評(píng)論 (0)編輯 收藏

    接受JMS消息的Message Driven Bean(Weblogic)

    一.WeblogicMDB類(lèi)(Message Driven Bean)
    import javax.ejb.EJBException;
    import javax.ejb.MessageDrivenBean;
    import javax.ejb.MessageDrivenContext;
    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.MessageListener;
    import javax.jms.TextMessage;
    import javax.naming.Context;
    import javax.naming.InitialContext;

    public class WeblogicMDB implements MessageDrivenBean, MessageListener {
        
    private static final long serialVersionUID = 5582665474886073061L;

        
    private MessageDrivenContext context;

        
    private Context jndiContext;

        
    public void setMessageDrivenContext(MessageDrivenContext context)
                
    throws EJBException {
            
    this.context = context;
            
    try {
                jndiContext 
    = new InitialContext();
            }
     catch (Exception ex) {
                ex.printStackTrace();
            }

        }


        
    public void ejbCreate() {

        }


        
    public void ejbRemove() {

        }


        
    public void onMessage(Message message) {
            
    if (message instanceof TextMessage) {
                
    //System.out.println("Yeah! I have received the TextMassage:");
                TextMessage txtmsg = (TextMessage) message;

                
    try {
                    System.out.println(
    "I have received the TextMassage:");
                    System.out.println(txtmsg.getText());
                }
     catch (JMSException e) {
                    e.printStackTrace();
                }

            }

        }

    }

    二.ejb-jar.xml
    <?xml version="1.0"?>
    <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_2_0.dtd">

    <ejb-jar>

     
    <enterprise-beans>

      
    <message-driven>
         
    <ejb-name>WeblogicMDBName</ejb-name>
         
    <ejb-class>WeblogicMDB</ejb-class>
         
    <transaction-type>Container</transaction-type>
         
    <message-driven-destination>
           
    <destination-type>javax.jms.Queue</destination-type>
         
    </message-driven-destination>
         
    <env-entry>
             
    <description>This is a bean listening on a queue.</description>
             
    <env-entry-name>listen_type</env-entry-name>
             
    <env-entry-type>java.lang.String</env-entry-type>
             
    <env-entry-value>queue</env-entry-value>
         
    </env-entry>
       
    </message-driven>
      
    </enterprise-beans>
    </ejb-jar>






    三.weblogic-ejb-jar.xml
    <?xml version="1.0"?>
    <!DOCTYPE weblogic-ejb-jar PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 8.1.0 EJB//EN' 'http://www.bea.com/servers/wls810/dtd/weblogic-ejb-jar.dtd'>

    <weblogic-ejb-jar>

        
    <weblogic-enterprise-bean>
            
    <ejb-name>WeblogicMDBName</ejb-name>
            
    <message-driven-descriptor>
                
    <pool>
                    
    <max-beans-in-free-pool>10</max-beans-in-free-pool>
                    
    <initial-beans-in-free-pool>
                        2
                    
    </initial-beans-in-free-pool>
                
    </pool>
                
    <destination-jndi-name>MyJMSQueue</destination-jndi-name>
                
    <initial-context-factory>
                    weblogic.jndi.WLInitialContextFactory
                
    </initial-context-factory>
                
    <provider-url>t3://127.0.0.1:7001/</provider-url>
                
    <connection-factory-jndi-name>
                    MyJMSConnectionFactory
                
    </connection-factory-jndi-name>
            
    </message-driven-descriptor>
        
    </weblogic-enterprise-bean>
    </weblogic-ejb-jar>


    使用上一篇文章中的QueueSupplier發(fā)送消息,輸出示例:


    過(guò)程很簡(jiǎn)單,值得注意的是系統(tǒng)的JDK最好和Weblogic使用的保持一致,至少不能存在代差.例如
    輸出消息我曾經(jīng)是這樣寫(xiě)的:
    System.out.println("I have received the TextMassage:"+txtmsg.getText());
    系統(tǒng)中的JDK1.5使用StringBuilder來(lái)把兩個(gè)字符串加在一起,而Weblogic自帶的1.4不認(rèn)識(shí)StringBuilder,就產(chǎn)生了異常.
    而制定Weblogic8.1的JDK為系統(tǒng)中的JDK1.5又會(huì)導(dǎo)致錯(cuò)誤. 所以,編程時(shí)建議JDK和Weblogic8.1的JDK保持一致,以避免發(fā)生莫明其妙的錯(cuò)誤.


    程序下載:
    http://m.tkk7.com/Files/sitinspring/WeblogicMDB20070910131749.rar

    posted @ 2008-02-22 12:17 和風(fēng)細(xì)雨 閱讀(687) | 評(píng)論 (0)編輯 收藏

    使用Spring2.0發(fā)送和接受JMS消息

         摘要: 1.JmsQueueSender類(lèi),用于發(fā)送消息 package com.sitinspring.springjms; import javax.jms.ConnectionFactory; import javax.jms.JMSException; import javax.jms.Message; import javax.jm...  閱讀全文

    posted @ 2008-02-22 12:16 和風(fēng)細(xì)雨 閱讀(665) | 評(píng)論 (0)編輯 收藏

    用匿名類(lèi)處理分類(lèi)匯總的方法

         摘要: 分類(lèi)匯總是統(tǒng)計(jì)中常用,舉例來(lái)說(shuō)如統(tǒng)計(jì)學(xué)生成績(jī),及格不及格的歸類(lèi),分優(yōu)良中差等級(jí)歸類(lèi)等,每個(gè)單項(xiàng)代碼很好寫(xiě),但是如果分類(lèi)匯總的項(xiàng)目多了,能一種匯總寫(xiě)一個(gè)函數(shù)嗎? 比如說(shuō)有些科目60分才算及格,有些科目50分就算;有些老師喜歡分優(yōu)良中差四等,有些老師卻喜歡分ABCD;不一而足,如果每個(gè)都寫(xiě)一個(gè)函數(shù)無(wú)疑是個(gè)編寫(xiě)和維護(hù)惡夢(mèng). 如果我們用匿名類(lèi)把分類(lèi)匯總的規(guī)則和分類(lèi)匯總的過(guò)程分別抽象出來(lái),代碼就清晰靈活多了...  閱讀全文

    posted @ 2008-02-22 12:15 和風(fēng)細(xì)雨 閱讀(391) | 評(píng)論 (0)編輯 收藏

    從薪水計(jì)算的例子看一段程序在不同環(huán)境中的變化

         摘要: 本例完整程序下載: http://m.tkk7.com/Files/sitinspring/TaxCaculator20071025203159.rar 世界天天在變,程序也一樣,唯一不變的只有變化二字.現(xiàn)代程序應(yīng)該隨著日新月異的環(huán)境而不斷變化,此之謂"物競(jìng)天擇,適者生存",下面的例子就演示了這一變化過(guò)程. 需求如下:(注:非真實(shí)稅率,僅僅是個(gè)例子)  &nb...  閱讀全文

    posted @ 2008-02-22 11:27 和風(fēng)細(xì)雨 閱讀(244) | 評(píng)論 (0)編輯 收藏

    三角形鑒別程序

         摘要: 需求:給出三角形的三邊長(zhǎng),判斷是否三角形,如是,判斷是等邊三角形,等腰三角形,不等邊三角形,銳角三角形,直角三角形和鈍角三角形,并計(jì)算出三角形的面積.     考查點(diǎn):建模的準(zhǔn)確性,思維的全面性,浮點(diǎn)數(shù)的比較. 補(bǔ)充知識(shí):cosA=b方+c方-a方/2*b*c package com.sitinspring; /** *//*...  閱讀全文

    posted @ 2008-02-22 11:25 和風(fēng)細(xì)雨 閱讀(315) | 評(píng)論 (0)編輯 收藏

    在Weblogic8上注冊(cè)并啟動(dòng)RMI程序.

    .做兩個(gè)類(lèi)Ruler和RulerImpl.
    import java.rmi.Remote;

    public interface Ruler extends Remote {
        
    public String getLength(String str) throws java.rmi.RemoteException;
    }

    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;

    import javax.naming.Context;
    import javax.naming.InitialContext;

    public class RulerImpl extends UnicastRemoteObject implements Ruler {
        
    public RulerImpl() throws RemoteException{
            
    super();
        }


        
    public String getLength(String str) throws java.rmi.RemoteException {
                     
    // 這里用Sb是因?yàn)閣eblogic的1.4的jdk不認(rèn)StringBuilder
            StringBuffer sb=new StringBuffer();
            sb.append(
    "String:");
            sb.append(str);
            sb.append(
    "'s length=");
            sb.append(str.length());
            
            
    return sb.toString();
        }

        
        
    public static void main(String[] args){
            
    try{
                RulerImpl rulerImpl
    =new RulerImpl();
                
                Context ctx
    =new InitialContext();
                ctx.bind(
    "StringRuler", rulerImpl);
            }

            
    catch(Exception ex){
                ex.printStackTrace();
            }

        }

    }

    2.用rmic編譯Ruler.class和RulerImpl.class 以生成樁類(lèi)RulerImpl_Stub.class.
    c:>C:\jdk1.5.0_09\bin\rmic RulerImpl.

    3.將生成的RulerImpl_Stub.class以及原有的Ruler.class和RulerImpl.class拷貝到服務(wù)器的目標(biāo)域中,本人機(jī)器上的是C:\bea\user_projects\domains\mydomain

    4.通過(guò)http://localhost:7001/console 進(jìn)入Weblogic控制臺(tái),并按 yourdomain->Deployment->Startup&Shutdown->Configure a New Startup Class 注冊(cè)啟動(dòng)類(lèi).完畢后結(jié)果如下圖:


    5.重新啟動(dòng)Server(Start Server)

    6.通過(guò)客戶端測(cè)試一下:
    import java.util.Hashtable;

    import javax.naming.Context;
    import javax.naming.InitialContext;

    public class RulerClient{
        
    public static void main(String[] args) throws Exception{
            Hashtable env
    =new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY, 
    "weblogic.jndi.WLInitialContextFactory");
            env.put(Context.PROVIDER_URL,
    "t3://localhost:7001");
            
            InitialContext ctx
    =new InitialContext(env);
            
            Object o
    =ctx.lookup("StringRuler");
            Ruler ruler
    =(Ruler)o;
            System.out.println(ruler.getLength(
    "123"));
        }

    }

    測(cè)試結(jié)果為:
    String:123's length=3

    代碼下載(rmic 目錄中包括三個(gè)已生成類(lèi)):
    http://m.tkk7.com/Files/sitinspring/RmiExample20071106220750.rar

    posted @ 2008-02-22 11:25 和風(fēng)細(xì)雨 閱讀(229) | 評(píng)論 (0)編輯 收藏

    僅列出標(biāo)題
    共10頁(yè): First 上一頁(yè) 2 3 4 5 6 7 8 9 10 下一頁(yè) 
    主站蜘蛛池模板: 在线精品亚洲一区二区三区| 亚洲中文字幕第一页在线| 亚洲热妇无码AV在线播放| 亚洲国产黄在线观看| 亚洲AV伊人久久青青草原| 久久亚洲AV永久无码精品| 亚洲精品乱码久久久久久下载| 亚洲AV无码一区二区三区牲色| 嫩草影院在线播放www免费观看| 青青青国产手机频在线免费观看| 成人免费无码大片A毛片抽搐 | 国产一区二区三区在线观看免费| 国产在线观看免费不卡| 免费在线黄色网址| 国产AV无码专区亚洲AV手机麻豆| 亚洲乱码一区二区三区在线观看| 亚洲成AV人片在线播放无码| 亚洲国产精品无码久久| 青青草97国产精品免费观看| 99久久免费国产特黄| 亚在线观看免费视频入口| 国产真人无遮挡作爱免费视频| 亚洲AⅤ优女AV综合久久久| 亚洲黄色中文字幕| 亚洲免费日韩无码系列| 成年性午夜免费视频网站不卡| 亚洲AV无码专区在线播放中文| 色婷婷精品免费视频| 黄页网站免费在线观看| 日本高清免费不卡在线| 亚洲自偷自拍另类图片二区| eeuss影院ss奇兵免费com| 国产青草视频在线观看免费影院| 亚洲高清日韩精品第一区 | 春意影院午夜爽爽爽免费| 波多野结衣在线免费观看| 国产∨亚洲V天堂无码久久久| 亚洲精品动漫在线| 国产猛男猛女超爽免费视频| 亚洲成a人无码av波多野按摩| 亚洲色中文字幕在线播放|