posts - 15,  comments - 9,  trackbacks - 0
          <2008年10月>
          2829301234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          常用鏈接

          留言簿(1)

          隨筆檔案

          文章檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

                    在大多數(shù)實際運行的多線程應用程序中,二個或多個線程需要共享對同一對象的訪問。如果二個線程訪問同一個對象,并且每個線程抖調(diào)用同一個方法,以便修改該對象的狀態(tài),那將出現(xiàn)什么樣的情況呢?
                  書中最常見的例子就是銀行取款的例子。假如一個人在銀行里開了10個帳戶,外面設置10個線程,每個帳戶一個線程。每個交易事務負責將一筆隨機數(shù)額的資金從該線程服務的帳戶轉(zhuǎn)移到另一個隨機帳戶。
                   在沒有對共享資源的訪問實施同步(synchronized)之前,在同時進行轉(zhuǎn)賬時,就會出現(xiàn)錯誤。例如下面一代代碼:

           

          public class UnsynchBankTest

             
          public static void main(String[] args)
             
          {  
                Bank b 
          = new Bank(NACCOUNTS, INITIAL_BALANCE);
                
          int i;
                
          for (i = 0; i < NACCOUNTS; i++)
                
          {  
                   TransferThread t 
          = new TransferThread(b, i,
                      INITIAL_BALANCE);
                   t.setPriority(Thread.NORM_PRIORITY 
          + i % 2);
                   t.start();
                }

             }


             
          public static final int NACCOUNTS = 10;
             
          public static final int INITIAL_BALANCE = 10000;
          }


          /** *//**
             A bank with a number of bank accounts.
          */

          class Bank

             
          /** *//**
                Constructs the bank.
                
          @param n the number of accounts
                
          @param initialBalance the initial balance
                for each account
             
          */

             
          public Bank(int n, int initialBalance)
             
          {  
                accounts 
          = new int[n];
                
          int i;
                
          for (i = 0; i < accounts.length; i++)
                   accounts[i] 
          = initialBalance;
                ntransacts 
          = 0;
             }


             
          /** *//**
                Transfers money from one account to another.
                
          @param from the account to transfer from
                
          @param to the account to transfer to
                
          @param amount the amount to transfer
             
          */

             
          public void transfer(int from, int to, int amount)
                
          throws InterruptedException
             
          {  
                accounts[from] 
          -= amount;
                accounts[to] 
          += amount;
                ntransacts
          ++;
                
          if (ntransacts % NTEST == 0) test();
             }


             
          /** *//**
                Prints a test message to check the integrity
                of this bank object.
             
          */

             
          public void test()
             
          {  
                
          int sum = 0;

                
          for (int i = 0; i < accounts.length; i++)
                   sum 
          += accounts[i];

                System.out.println(
          "Transactions:" + ntransacts
                   
          + " Sum: " + sum);
             }


             
          /** *//**
                Gets the number of accounts in the bank.
                
          @return the number of accounts
             
          */

             
          public int size()
             
          {  
                
          return accounts.length;
             }


             
          public static final int NTEST = 10000;
             
          private final int[] accounts;
             
          private long ntransacts = 0;
          }


          /** *//**
             A thread that transfers money from an account to other
             accounts in a bank.
          */

          class TransferThread extends Thread
          {  
             
          /** *//**
                Constructs a transfer thread.
                
          @param b the bank between whose account money is transferred
                
          @param from the account to transfer money from
                
          @param max the maximum amount of money in each transfer 
             
          */

             
          public TransferThread(Bank b, int from, int max)
             
          {  
                bank 
          = b;
                fromAccount 
          = from;
                maxAmount 
          = max;
             }


             
          public void run()
             
          {  
                
          try
                
          {  
                   
          while (!interrupted())
                   
          {  
                      
          for (int i = 0; i < REPS; i++)
                      
          {
                         
          int toAccount = (int)(bank.size() * Math.random());
                         
          int amount = (int)(maxAmount * Math.random() / REPS);
                         bank.transfer(fromAccount, toAccount, amount);
                         sleep(
          1);
                      }

                   }

                }

                
          catch(InterruptedException e) {}
             }


             
          private Bank bank;
             
          private int fromAccount;
             
          private int maxAmount;
             

          運行一段時間后會發(fā)現(xiàn),sum(總金額發(fā)生了變化)。
          下面這段代碼是對共享資源的訪問實施同步:

          public class SynchBankTest

             
          public static void main(String[] args)
             
          {  
                Bank b 
          = new Bank(NACCOUNTS, INITIAL_BALANCE);
                
          int i;
                
          for (i = 0; i < NACCOUNTS; i++)
                
          {  
                   TransferThread t 
          = new TransferThread(b, i,
                      INITIAL_BALANCE);
                   t.setPriority(Thread.NORM_PRIORITY 
          + i % 2);
                   t.start();
                }

             }


             
          public static final int NACCOUNTS = 10;
             
          public static final int INITIAL_BALANCE = 10000;
          }


          /**
             A bank with a number of bank accounts.
          */

          class Bank

             
          /**
                Constructs the bank.
                
          @param n the number of accounts
                
          @param initialBalance the initial balance
                for each account
             
          */

             
          public Bank(int n, int initialBalance)
             
          {  
                accounts 
          = new int[n];
                
          int i;
                
          for (i = 0; i < accounts.length; i++)
                   accounts[i] 
          = initialBalance;
                ntransacts 
          = 0;
             }


             
          /**
                Transfers money from one account to another.
                
          @param from the account to transfer from
                
          @param to the account to transfer to
                
          @param amount the amount to transfer
             
          */

             
          public synchronized void transfer(int from, int to, int amount)
                
          throws InterruptedException
             
          {  
                
          while (accounts[from] < amount)
                   wait();
                accounts[from] 
          -= amount;
                accounts[to] 
          += amount;
                ntransacts
          ++;
                notifyAll();
                
          if (ntransacts % NTEST == 0) test();
             }


             
          /**
                Prints a test message to check the integrity
                of this bank object.
             
          */

             
          public synchronized void test()
             
          {  
                
          int sum = 0;

                
          for (int i = 0; i < accounts.length; i++)
                   sum 
          += accounts[i];

                System.out.println(
          "Transactions:" + ntransacts
                   
          + " Sum: " + sum);
             }


             
          /**
                Gets the number of accounts in the bank.
                
          @return the number of accounts
             
          */

             
          public int size()
             
          {  
                
          return accounts.length;
             }


             
          public static final int NTEST = 10000;
             
          private final int[] accounts;
             
          private long ntransacts = 0;
          }


          /**
             A thread that transfers money from an account to other
             accounts in a bank.
          */

          class TransferThread extends Thread
          {  
             
          /**
                Constructs a transfer thread.
                
          @param b the bank between whose account money is transferred
                
          @param from the account to transfer money from
                
          @param max the maximum amount of money in each transfer 
             
          */

             
          public TransferThread(Bank b, int from, int max)
             
          {  
                bank 
          = b;
                fromAccount 
          = from;
                maxAmount 
          = max;
             }


             
          public void run()
             
          {  
                
          try
                
          {  
                   
          while (!interrupted())
                   
          {  
                      
          int toAccount = (int)(bank.size() * Math.random());
                      
          int amount = (int)(maxAmount * Math.random());
                      bank.transfer(fromAccount, toAccount, amount);
                      sleep(
          1);
                   }

                }

                
          catch(InterruptedException e) {}
             }


             
          private Bank bank;
             
          private int fromAccount;
             
          private int maxAmount;
          }


          運行后,sum未發(fā)生變化。
          簡要說明一下同步機制是如何運行的:
          1.若要調(diào)用synchronized方法,隱含參數(shù)不應該被鎖定。調(diào)用該方法便可鎖定該對象。而從該調(diào)用返回則可撤銷對隱含參數(shù)對象的鎖定。因此,每次只有一個線程能夠在特定對象上執(zhí)行synchronized方法。
          2.當一個線程執(zhí)行對wait方法的調(diào)用時,他將釋放對象鎖,而且進入該對象的等待列表。
          3.要從等待列表中刪除一個線程,另外的莫個線程必須調(diào)用同一對象上的notifyALL或notify方法。
               調(diào)度原則確實是復雜的,不過使用起來是相對簡單的。你只要按照下面的5條原則進行操作即可:
          1.如果二個或多個線程修改一個對象,請將執(zhí)行修改的方法聲明為synchronized方法。受到對象修改影響的只讀方法也必須實現(xiàn)同步。
          2.如果一個線程必須等待某個對象的狀態(tài)出項變更,那么它應該在對象的內(nèi)部等待,而不是在外邊等待,這可以通過輸入一個synchronized方法,并調(diào)用wait方法實現(xiàn)。
          3.不要在synchronized方法中花費大量的時間。大多數(shù)操作只是更新數(shù)據(jù)結(jié)構(gòu),然后很快返回。如果你不能立即完成synchronized方法的操作,那么請調(diào)用wait方法,這樣你就可以在等待時釋放該對象鎖。
          4.每當一個方法改變某個對象的狀態(tài)時,太就應該調(diào)用notifyALL方法。這樣可以給等待的線程一個機會,以便查看環(huán)境有沒有發(fā)生變化。
          5.請記住,wait和notifyALL/notify方法都屬于Object類的方法,而不是Thread類的方法。請反復檢查你對wait方法的調(diào)用同一對象上的通知是否匹配。

           

           

          posted on 2008-10-19 21:23 侖波比 閱讀(205) 評論(0)  編輯  收藏

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


          網(wǎng)站導航:
           
          主站蜘蛛池模板: 冀州市| 卢氏县| 松潘县| 韶关市| 三台县| 荆州市| 华安县| 永济市| 桑日县| 双鸭山市| 彰化市| 汪清县| 正蓝旗| 宁明县| 德惠市| 衡阳县| 陇川县| 定西市| 印江| 宁安市| 海宁市| 夏津县| 博白县| 灵川县| 金沙县| 竹山县| 河北省| 临潭县| 汕头市| 屯昌县| 灵石县| 大港区| 宜昌市| 靖边县| 平邑县| 公主岭市| 沐川县| 读书| 柳州市| 额济纳旗| 思南县|