OMG,到底在尋找什么..................
          (構(gòu)造一個(gè)完美的J2EE系統(tǒng)所需要的完整知識體系)
          posts - 198,  comments - 37,  trackbacks - 0
          原貼地址:http://www.gbunix.com/htmldata/2004_12/14/19/article_768_1.html

          我在22號的筆記中不是有一個(gè)疑問嗎?為什么我編的程序沒有不同步的現(xiàn)象產(chǎn)生呢,我把它發(fā)到csdn上去了,現(xiàn)在我已經(jīng)基本解決這個(gè)問題了,下面是論壇的回復(fù)紀(jì)錄摘要

          回復(fù)人:bluesmile979(笑著) ( ) 信譽(yù):100? 2003-01-22 21:08:00? 得分:0
          說說我的看法,我認(rèn)為最大的問題在于多線程,看了你的代碼,好像只有兩個(gè)線成了。而例子中應(yīng)該是比較多的線程,多個(gè)線程競爭時(shí)間片,被打斷的幾率自然就大得多了。就算你加了循環(huán),由于機(jī)器的運(yùn)算速度,仍然沒有多個(gè)線程競爭那么現(xiàn)象明顯。不知道各位以為如何。

          回復(fù)人:xm4014(forrest) ( ) 信譽(yù):100? 2003-01-22 22:07:00? 得分:0
          to bluesmile979(笑著)
          我也曾經(jīng)想到過是否因?yàn)榫€程太少而導(dǎo)致,但是我將Think in java的例程中的兩個(gè)參數(shù)都設(shè)為1來運(yùn)行,那么最后也就和我寫的程序一樣,只有兩個(gè)線程,結(jié)果照樣有不同步.這又怎么解釋呢

          回復(fù)人:tianfeichen(側(cè)耳傾聽) ( ) 信譽(yù):110? 2003-01-22 23:57:00? 得分:0
          線程的安排畢竟是隨機(jī)的,很少會(huì)有不同步的出現(xiàn),次數(shù)少了不容易發(fā)現(xiàn)。
          我常用的方法是,先讓無限循環(huán)開始,循環(huán)的時(shí)候也不要求輸出什么的,只加上一個(gè)停止的條件,比如:
          if (counter1 != counter2)
          {
          ?? System.out.println(counter1 + " ," + counter2)
          ?? System.exit(0);
          }

          剩下的就是等了,一般十幾秒甚至幾秒就出結(jié)果了,可以發(fā)現(xiàn)記數(shù)已經(jīng)到幾十萬或者幾百萬了。

          如果同時(shí)開了5個(gè)線程,等了一分鐘,我就算是它同步了。

          我的方法可能不太科學(xué),不過效果挺好。

          回復(fù)人: xm4014(forrest) ( ) 信譽(yù):100? 2003-01-23 11:44:00? 得分:0
          可以幫我調(diào)試一下嗎?為什么我按照你的方法卻始終沒有得到結(jié)果呢?

          將下面的代碼直接拷貝就可以了,程序名為Sharing2.java,版本是1.4.1

          class TwoCounter extends Thread {
          ? private int count1 = 0, count2 = 0;
          ? private boolean started=false;
          ? public void start(){
          ??? if (!started)
          ??? {
          ????? started=true;
          ????? super.start();
          ??? }
          ? }
          ? public void run() {
          ??? while (true) {
          ??????? count1++;
          ??????? count2++;
          //????? System.out.println("Count1="+count1+",Count2="+count2);
          ????? try {
          ??????? sleep(500);
          ????? } catch (InterruptedException e){System.out.println("TwoCounter.run");}
          ?? }
          ? }

          ? public void synchTest() {
          //??? Sharing2.incrementAccess();
          ??? if(count1 != count2)
          ????? {System.out.println(count1+","+count2);
          ?????? System.exit(0);
          ????? }
          ? }
          }

          class Watcher extends Thread {
          ? private Sharing2 p;
          ? public Watcher(Sharing2 p) {
          ??? this.p = p;
          ??? start();
          ? }
          ? public void run() {
          ??? while(true) {
          ????? p.s.synchTest();
          ????? try {
          ??????? sleep(500);
          ????? } catch (InterruptedException e){System.out.println("Watcher.run");}
          ??? }
          ? }
          }

          public class Sharing2 {
          ? TwoCounter s;
          ? private static int accessCount = 0;
          ? public static void incrementAccess() {
          //??? accessCount++;
          //??? System.out.println("accessCount="+accessCount);
          ? }
          ? public static void main(String[] args) {
          ??? Sharing2 aaa = new Sharing2();
          ??? aaa.s=new TwoCounter();
          ??? aaa.s.start();
          ??? new Watcher(aaa);
          ? }
          } ///:~

          另外,根據(jù)你的意思,我的程序是沒有問題的,只是線程少了,不同步很難產(chǎn)生,要等到counter增加到很大數(shù)目的時(shí)候才有可能,對嗎?

          回復(fù)人: hey_you(Hey) ( ) 信譽(yù):100? 2003-01-23 13:27:00? 得分:0

          我是這樣想的:不同步而發(fā)生沖突是一種可能性,而sychronize是讓這種可能性為0。你沒有1發(fā)現(xiàn)不同步,并不能證明永遠(yuǎn)都不會(huì)發(fā)生不同步的情況,那只是一個(gè)時(shí)間問題。系統(tǒng)對線程的調(diào)度受了環(huán)境的影響,要是你機(jī)器上同時(shí)還跑了很多程序,可能情況就不同了。

          回復(fù)人: xm4014(forrest) ( ) 信譽(yù):100? 2003-01-23 15:56:00? 得分:0
          呵呵,我用tianfeichen(側(cè)耳傾聽)的方法運(yùn)行的程序,也就是我上面貼的代碼居然有結(jié)果了,counter1= 217327,counter2=217356,還真想差的不少。但是時(shí)間上絕不是一兩分鐘那么簡單,至少過了兩個(gè)小時(shí),可能真是我和他的運(yùn)行環(huán)境的不同造成的.正如hey_you(Hey)所說,只是一個(gè)時(shí)間問題.

          希望其它人能給出更多的看法,如果覺得沒必要再討論下去,那我就接貼.

          回復(fù)人: bluesmile979(笑著) ( ) 信譽(yù):100? 2003-01-23 16:38:00? 得分:0
          我考,一兩個(gè)小時(shí)你也能堅(jiān)持,服了。

          我認(rèn)為問題結(jié)果也就兩點(diǎn)了。一個(gè)就是我認(rèn)為的線程數(shù)量

          另一個(gè)就是你認(rèn)為的setText會(huì)有比較多的處理,占用比較多的資源。

          兩種情況都會(huì)影響到這個(gè)問題的出現(xiàn)幾率:)樓主宰總結(jié)一下吧,呵呵。

          回復(fù)人: linliangyi(藍(lán)山咖啡) ( ) 信譽(yù):100? 2003-01-23 17:10:00? 得分:0
          sleep(500)占用的時(shí)間勝過for(5000)的時(shí)間,因此線程在sleep中被切換的概率遠(yuǎn)勝于在for中被中斷的概率!!(回頭去看我的程序就知道了)

          事實(shí)上,兩個(gè)變量從不相等變?yōu)橄嗟龋钦f明了不同步!!

          順便說一下關(guān)于swing和awt控件在線程中操作時(shí),比如setText,常造成很多意外
          樓主可以看看相關(guān)的書籍!!

          回復(fù)人: xm4014(forrest) ( ) 信譽(yù):100? 2003-01-24 14:25:00? 得分:0
          我將各位的觀點(diǎn)綜合起來總結(jié)一下:

          首先要肯定的是,假如不使用synchronized關(guān)鍵字來定義同步方法或者定義同步塊,那么,發(fā)生不同步的可能是絕對存在的,反過來說,synchronized就是讓這種可能性為0.

          在第一種情況下,發(fā)生不同步的可能雖然存在,但是它的幾率受到以下幾個(gè)方面因素的影響

          1.在不同的操作系統(tǒng)及運(yùn)行環(huán)境下,捕捉到不同步的幾率可能就不一樣,或者說等待的時(shí)間可能就有長有短
          2.程序中線程數(shù)目的多寡,如果線程太少,那么這種不同步就難于捕捉到,可能需要等待很長的時(shí)間
          3.代碼本身的影響.比如使用awt類中涉及到GUI的方法,可能就會(huì)占用較多的資源,造成很多意外,那么發(fā)生沖突的可能性就大得多
          4.線程是由操作系統(tǒng)隨機(jī)分配的,本來就存在著不確定性,這種不確定性也會(huì)影響最后的結(jié)果

          不知道是否正確,大家還有什么補(bǔ)充呢?

          明天正式結(jié)帖

          不過說實(shí)話,我有點(diǎn)搞不懂,為什么最后的結(jié)果,counter1(217327)和counter2(217356)會(huì)相差那么多呢.按照我的程序,即便watcher線程插到兩個(gè)自加的語句中間來,檢測到的這兩個(gè)計(jì)數(shù)器之間的差異頂多也就是1啊.出現(xiàn)這么大的差異,只可能是某一個(gè)計(jì)數(shù)器的自加語句有好多次在根本沒有運(yùn)行的情況下就被強(qiáng)行中斷了.這就太恐怖了!雖然有其它線程的存在會(huì)干擾當(dāng)前線程,但是也不至于讓當(dāng)前線程語句不運(yùn)行吧,最多也就是等等再運(yùn)行啊?我有點(diǎn)糊涂了,操作系統(tǒng)沒學(xué)好,如果大家不嫌麻煩,清幫我解釋一下吧

          結(jié)果現(xiàn)在又有新的問題,我想又要等到明天才有答案吧

          但我們今天可以解決另一個(gè)涉及到synchronized的問題.這是我在論壇上看到的一個(gè)貼子.正是因?yàn)槲医鉀Q不了,我才認(rèn)為有必要回頭來好好研究線程和同步等內(nèi)容的.
          問題如下:

          file://分析這段程序,并解釋一下,著重講講synchronized、wait(),notify 謝謝!
          class ThreadA
          {
          ? public static void main(String[] args)
          ? {
          ??? ThreadB b=new ThreadB();
          ??? b.start();
          ??? System.out.println("b is start....");
          ??? synchronized(b)//括號里的b是什么意思,起什么作用?
          ??? {
          ????? try
          ????? {
          ?System.out.println("Waiting for b to complete...");
          ?b.wait();//這一句是什么意思,究竟讓誰wait?
          ??????? System.out.println("Completed.Now back to main thread");
          ????? }catch (InterruptedException e){}
          ??? }
          ??? System.out.println("Total is :"+b.total);
          ?? }
          }

          class ThreadB extends Thread
          {
          ? int total;
          ? public void run()
          ? {
          ??? synchronized(this)
          ??? {
          ????? System.out.println("ThreadB is running..");
          ????? for (int i=0;i<100;i++ )
          ????? {
          ??????? total +=i;
          ??????? System.out.println("total is "+total);
          ????? }
          ????? notify();
          ??? }
          ? }
          }

          要分析這個(gè)程序,首先要理解notify()和wait(),為什么在前幾天紀(jì)錄線程的時(shí)候沒有紀(jì)錄這兩個(gè)方法呢,因?yàn)檫@兩個(gè)方法本來就不屬于Thread類,而是屬于最底層的object基礎(chǔ)類的,也就是說不光是Thread,每個(gè)對象都有notify和wait的功能,為什么?因?yàn)樗麄兪怯脕聿倏v鎖的,而每個(gè)對象都有鎖,鎖是每個(gè)對象的基礎(chǔ),既然鎖是基礎(chǔ)的,那么操縱鎖的方法當(dāng)然也是最基礎(chǔ)了.

          再往下看之前呢,首先最好復(fù)習(xí)一下Think in Java的14.3.1中第3部分內(nèi)容:等待和通知,也就是wait()和notify了.

          按照Think in Java中的解釋:"wait()允許我們將線程置入“睡眠”狀態(tài),同時(shí)又“積極”地等待條件發(fā)生改變.而且只有在一個(gè)notify()或notifyAll()發(fā)生變化的時(shí)候,線程才會(huì)被喚醒,并檢查條件是否有變."

          我們來解釋一下這句話.

          "wait()允許我們將線程置入“睡眠”狀態(tài)",也就是說,wait也是讓當(dāng)前線程阻塞的,這一點(diǎn)和sleep或者suspend是相同的.那和sleep,suspend有什么區(qū)別呢?

          區(qū)別在于"(wait)同時(shí)又“積極”地等待條件發(fā)生改變",這一點(diǎn)很關(guān)鍵,sleep和suspend無法做到.因?yàn)槲覀冇袝r(shí)候需要通過同步(synchronized)的幫助來防止線程之間的沖突,而一旦使用同步,就要鎖定對象,也就是獲取對象鎖,其它要使用該對象鎖的線程都只能排隊(duì)等著,等到同步方法或者同步塊里的程序全部運(yùn)行完才有機(jī)會(huì).在同步方法和同步塊中,無論sleep()還是suspend()都不可能自己被調(diào)用的時(shí)候解除鎖定,他們都霸占著正在使用的對象鎖不放.

          而wait卻可以,它可以讓同步方法或者同步塊暫時(shí)放棄對象鎖,而將它暫時(shí)讓給其它需要對象鎖的人(這里應(yīng)該是程序塊,或線程)用,這意味著可在執(zhí)行wait()期間調(diào)用線程對象中的其他同步方法!在其它情況下(sleep啊,suspend啊),這是不可能的.

          但是注意我前面說的,只是暫時(shí)放棄對象鎖,暫時(shí)給其它線程使用,我wait所在的線程還是要把這個(gè)對象鎖收回來的呀.wait什么?就是wait別人用完了還給我啊!

          好,那怎么把對象鎖收回來呢?

          第一種方法,限定借出去的時(shí)間.在wait()中設(shè)置參數(shù),比如wait(1000),以毫秒為單位,就表明我只借出去1秒中,一秒鐘之后,我自動(dòng)收回.

          第二種方法,讓借出去的人通知我,他用完了,要還給我了.這時(shí),我馬上就收回來.哎,假如我設(shè)了1小時(shí)之后收回,別人只用了半小時(shí)就完了,那怎么辦呢?靠!當(dāng)然用完了就收回了,還管我設(shè)的是多長時(shí)間啊.

          那么別人怎么通知我呢?相信大家都可以想到了,notify(),這就是最后一句話"而且只有在一個(gè)notify()或notifyAll()發(fā)生變化的時(shí)候,線程才會(huì)被喚醒"的意思了.

          因此,我們可將一個(gè)wait()和notify()置入任何同步方法或同步塊內(nèi)部,無論在那個(gè)類里是否準(zhǔn)備進(jìn)行涉及線程的處理。而且實(shí)際上,我們也只能在同步方法或者同步塊里面調(diào)用wait()和notify().

          這個(gè)時(shí)候我們來解釋上面的程序,簡直是易如反掌了.

          synchronized(b){...};的意思是定義一個(gè)同步塊,使用b作為資源鎖。b.wait();的意思是臨時(shí)釋放鎖,并阻塞當(dāng)前線程,好讓其他使用同一把鎖的線程有機(jī)會(huì)執(zhí)行,在這里要用同一把鎖的就是b線程本身.這個(gè)線程在執(zhí)行到一定地方后用notify()通知wait的線程,鎖已經(jīng)用完,待notify()所在的同步塊運(yùn)行完之后,wait所在的線程就可以繼續(xù)執(zhí)行.

          posted on 2006-11-22 10:14 OMG 閱讀(233) 評論(0)  編輯  收藏 所屬分類: Soket

          <2006年11月>
          2930311234
          567891011
          12131415161718
          19202122232425
          262728293012
          3456789

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          IT風(fēng)云人物

          文檔

          朋友

          相冊

          經(jīng)典網(wǎng)站

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 辽源市| 全州县| 临安市| 赞皇县| 富源县| 景德镇市| 乳源| 苏尼特左旗| 阳谷县| 仁化县| 卓尼县| 翼城县| 邯郸县| 平陆县| 长治市| 辽宁省| 怀宁县| 德兴市| 上蔡县| 乐平市| 西峡县| 武乡县| 巴青县| 长宁区| 乌恰县| 江门市| 扶余县| 三穗县| 东乌珠穆沁旗| 榆社县| 信宜市| 广河县| 惠安县| 岑溪市| 扎囊县| 积石山| 乌鲁木齐市| 鱼台县| 郯城县| 明溪县| 锡林浩特市|