posts - 37, comments - 8, trackbacks - 0, articles - 0

          java基礎(chǔ):關(guān)于線程

          Posted on 2008-08-02 11:10 夢與橋 閱讀(404) 評論(1)  編輯  收藏 所屬分類: java基礎(chǔ)

          1、作用:使java應(yīng)用程序同時(shí)完成多項(xiàng)任務(wù),當(dāng)其一個(gè)線程被阻塞時(shí),只有那個(gè)被阻塞的線程暫停,所有其他線程繼續(xù)執(zhí)行。
          2、概念:一個(gè)java程序可以包含多個(gè)線程,每個(gè)線程具有部分程序功能,能與其他線程同時(shí)執(zhí)行,這種能力稱為多線程。
          3、線程只是在系統(tǒng)層被實(shí)現(xiàn),核心編程語言需要一個(gè)特定的編程接口來實(shí)現(xiàn)。在java中,創(chuàng)建線程的方法有兩種,其一是繼承Thread類,其二是實(shí)現(xiàn)Runnable接口。

          繼承Thread類實(shí)例:
          class MyThread extends Thread
          {
           int count=1,num;static int COUNT=1;
           MyThread(int num)
           {
            this.num=num;
            System.out.println("創(chuàng)建線程"+num);
           }
           public void run()
           {
            while(true)
            {
             System.out.println("線程"+num+"統(tǒng)計(jì):"+count+";總統(tǒng)計(jì):"+(COUNT++));
             if((++count)>6)
              return;
            }
           }
          }
          public class Test
          {
           public static void main(String args[])
           {
            for(int i=0;i<5;i++)
             new MyThread(i).start();
           }
          }

          實(shí)現(xiàn)Runnable接口實(shí)例:
          class MyThread implements Runnable
          {
           int count=1,num;static int COUNT=1;
           MyThread(int num)
           {
            this.num=num;
            System.out.println("創(chuàng)建線程"+num);
           }
           public void run()  //覆蓋run()方法
           {
            while(true)
            {
             System.out.println("線程"+num+"統(tǒng)計(jì):"+count+";總統(tǒng)計(jì):"+(COUNT++));
             if((++count)>6)
              return;
            }
           }
          }
          public class Test
          {
           public static void main(String args[])
           {
            //構(gòu)造線程過程:Runnable target=new MyThread();
           // 構(gòu)造線程過程續(xù):Thread myThread=new Thread(taget);
            for(int i=0;i<5;i++)
             new Thread(new MyThread(i)).start();//Thread的構(gòu)造函數(shù)實(shí)現(xiàn)之
           }
          }

          兩種創(chuàng)建線程試方式的比較:
                      §實(shí)現(xiàn)Runnable的優(yōu)點(diǎn):java的單一繼承機(jī)制,使用戶只能采用實(shí)現(xiàn)Runnable方法。
                      §繼承Thread的優(yōu)點(diǎn):當(dāng)一個(gè)run()方法體現(xiàn)在繼承Thread類的類中,用this指向?qū)嶋H控制運(yùn)行的Thread實(shí)例,不需要如下控制:T hread.currentThread().jion(),而可以簡單地寫為:jion()。
                      §使用 Runnable 接口來實(shí)現(xiàn)多線程使得我們能夠在一個(gè)類中包容所有的代碼,有利于封裝,它的缺點(diǎn)在于,我們只能使用一套代碼,若想創(chuàng)建多個(gè)線程并使各個(gè)線程執(zhí)行不同的代碼,則仍必須額外創(chuàng)建類,如果這樣的話,在大多數(shù)情況下也許還不如直接用多個(gè)類分別繼承 Thread 來得緊湊。
          4、線程生命周期基本狀態(tài)圖:

          一個(gè)Thread對象在它的生命周期中會處于以下幾種狀態(tài):
                  §新建狀態(tài)(New Thread):線程已創(chuàng)建、實(shí)例化完畢,還未執(zhí)行方法體run()以啟動該線程。
                  §就緒狀態(tài)/可運(yùn)行狀態(tài)(Runnable):已調(diào)用start方法,為該線程完成登記工作和分配資源工作。可以用isAlive()方法識別一個(gè)線程是否處于runnable狀態(tài),若是返回true,否則返回false。
                  §運(yùn)行狀態(tài)(Running):線程調(diào)度器為其分配了CPU時(shí)間,處于運(yùn)行狀態(tài)。
                  §阻塞/掛起狀態(tài)(Wait/Block):等待某個(gè)事件發(fā)生,一旦發(fā)生就離開該狀態(tài),進(jìn)入Runnable狀態(tài)。通常在調(diào)用sleep或wait方法進(jìn)入該狀態(tài),I/O阻塞時(shí)也可進(jìn)入該狀態(tài),或發(fā)生在多線程同步訪問時(shí),線程試圖鎖住已被另一個(gè)線程鎖住的對象。
                  §終止?fàn)顟B(tài)(Dead):run方法執(zhí)行完畢,或非預(yù)期的異常發(fā)生導(dǎo)致run方法終止,使線程死亡,此時(shí)不可重新啟動,與普通對象沒有區(qū)別。

           5、一個(gè)多線程的實(shí)例:
          class NewThread implements Runnable
          {
           String name;
           Thread t;
           NewThread(String name)
           {
            this.name=name;
            t=new Thread(this,name);
            System.out.println("New thread:"+t);
            t.start();
           }
           public void run()
           {
            try
            {
             for(int i=3;i>0;i--)
              Thread.sleep(1000);//使一個(gè)線程暫停執(zhí)行一段時(shí)間
            }
            catch (InterruptedException e)
            {
             System.out.println(name+"Interrupted");
            }
            System.out.println(name+"   exting.");
           }
          }
          public class Test
          {
           public static void main(String args[])
           {
            NewThread nt1=new NewThread("First");
            NewThread nt2=new NewThread("Second");
            NewThread nt3=new NewThread("Third");
            //isAlive()方法用來測試其調(diào)用的線程是否仍在運(yùn)行
            System.out.println("IsAlive(First):"+nt1.t.isAlive());
            System.out.println("IsAlive(Second):"+nt2.t.isAlive());
            System.out.println("IsAlive(Third):"+nt3.t.isAlive());
            try
            {
             System.out.println("Waiting for threads to finish.");
             //等待調(diào)用jion()的線程直到結(jié)束語
             nt1.t.join();
             nt2.t.join();
             nt3.t.join();
            }
            catch (InterruptedException e)
            {
             System.out.println("Main thread Interrupted");
            }
            //isAlive()方法用來測試其調(diào)用的線程是否仍在運(yùn)行
            System.out.println("IsAlive(First):"+nt1.t.isAlive());
            System.out.println("IsAlive(Second):"+nt2.t.isAlive());
            System.out.println("IsAlive(Third):"+nt3.t.isAlive());
            System.out.println("Main thread exiting.");
           }
          }
          運(yùn)行結(jié)果:

          本例子實(shí)現(xiàn)了主線程最后結(jié)束,方法是子線程調(diào)用join()方法,讓主線程等待其結(jié)束。

          6、一個(gè)故事及和這個(gè)故事有關(guān)的線程問題:
          故事:一男仙一女妖,偶然邂逅,真情相生,從此纏綿一處,不誤正業(yè)。仙的上司聽說后,非常惱火,上告玉帝,玉帝授權(quán)給他,讓他懲治這一對仙妖冤家。他一直在想如何懲治時(shí),一日到牢中發(fā)現(xiàn),女妖正用勺子喂男仙,監(jiān)獄的飯菜很差,但這一對其樂融融。他冷然一笑,走出牢房,對技術(shù)員說:“你給我編寫一個(gè)程序,置入他們腦子里面,讓一個(gè)永遠(yuǎn)不停地喂,一個(gè)永遠(yuǎn)不停地吃。”技術(shù)員眨了一會眼睛,“這個(gè)有兩個(gè)問題,一是喂完了一勺子后,要停下來去取,這要男仙去等;在男仙嘴中塞滿沒有咽到肚里時(shí),舉起勺子的女妖要等,所以……”“這是你的事,你自己看著辦。”技術(shù)員眨了一下眼睛退下,回到辦公室,偶一思索,打開電腦,寫出如下程序:

          class Food
          {
           int n;
           //標(biāo)志,為false不允許咬,為true允許咬
           boolean blnValue=false;
           synchronized int get()
           {
            try
            {//如果沒有食物,男仙等待
             wait();
            }
            catch (InterruptedException e)
            {
             System.out.println("InterruptedException caught");
            }
            //開吃,同時(shí)告訴女妖要盛飯了
            System.out.println("Got:"+n);
            blnValue=false;
            notify();
            return n;
           }
           synchronized void put(int n)
           {
            if(blnValue)
             try
             {//如果還沒吃完,女妖等待
              wait();
             }
             catch (InterruptedException e)
             {
              System.out.println("InterruptedException caught");
             }
             //去取食物,同時(shí)告訴男仙
             this.n=n;
             blnValue=true;
             System.out.println("Put: "+n);
             notify();
           }
          }
          class Immortal implements Runnable
          {
           Food f;
           Immortal(Food f)
           {
            this.f=f;
            new Thread(this,"Immortal").start();
           }
           public void run()
           {
            while(true)
            {
             f.get();
            }
           }

          }
          class Goblin implements Runnable
          {
           Food f;
           Goblin(Food f)
           {
            this.f=f;
            new Thread(this,"Goblin").start();
           }
           public void run()
           {
            int i=1;
            while(true)
            {
             f.put(i++);
            }
           }
          }
          class Test
          {
           public static void main(String args[])
           {
            Food f=new Food();
            new Immortal(f);
            new Goblin(f);
            System.out.println("問世間情為何物,叫人喂而不倦,吃而不倦:");
           }
          }

          技術(shù)員拿著程序去見上司,上司讓它運(yùn)行一遍,他運(yùn)行之。上司點(diǎn)了點(diǎn)頭,從抽屜里拿出一疊鈔票,遞給他說:“這是你的特別獎(jiǎng)金,但是我要告訴你這不是因你的程序而發(fā)——這個(gè)程序我似曾相識啊,是因?yàn)槟愕倪@句:‘問世間情為何物,叫人喂而不倦,吃而不倦。’真是妙極了,是一種無恥的幸災(zāi)樂禍者,最想吟上800遍的啊。真希望,他們你喂我吃時(shí),圍著一圈人高唱這句啊。”“你說,這段程序你似曾相識?”“是啊,我也在學(xué)JAVA啊,挺好玩的嘛,線程我剛學(xué)了沒多久。”
          出了上司的辦公室,技術(shù)員的衣服都濕了一片,回去后想了很久,第二天辭了職。當(dāng)別人問及原因,他說:“偶在這壓力太大,已經(jīng)無法承受。”在一片惋惜中他離開了仙界,終于一次在酒后他說:“唉,我的那個(gè)上司沒有人性啊,我怕。”“去,瞧你說,仙哪有人性,仙有仙品。”“那他是沒有仙品了,反正是一種該有的東西他沒有。”

          7、百獸之王大宴賓客及線程優(yōu)先級問題
          百獸之王,偶逢佳運(yùn),得一至寶,欣喜若狂,于是大宴賓客,以示慶賀。設(shè)宴當(dāng)日,高朋滿座,良友如云,大家舉杯相碰,其聲清脆。百獸之王聽之,捻須而笑。忽然一迎賓者慌張跑來,“報(bào)告大王,不好了,一群黑壓壓的飛蟲正往這邊飛來。”“今日來者均為客,奏樂歡迎。”“來得太多了,怕我把全部的食物拿出來,也不夠招待他們的。”“奶奶個(gè)熊的,真是傳說中的乞丐飛團(tuán),待我察看一下。”
          百獸之王來到門外,搭眼一瞧,顏有所失,轉(zhuǎn)首對狐貍說:“這個(gè)事情你去處理。”“是,大王。”狐貍答應(yīng)之后,眼睛咕嚕一轉(zhuǎn),計(jì)上心來,拿出手機(jī)來。
          “喂,老兄,最近忙什么呢?”
          “鼓搗JAVA啊。”
          “功力有大增吧?”
          “還好了,嘛事啊?”
          “我有個(gè)問題,想請你幫個(gè)忙?”
          “老朋友了,好說,不過,我有很長時(shí)間沒有喝過酒了。”
          “哈哈,放心吧,今天我們大王大宴賓客,款待貴賓的十瓶酒有你一瓶。”
          “兩瓶吧。”
          “你TMD的真厲害,好吧,但你可得保證我們大王滿意。”
          “皆大歡喜,說吧,什么事?”狐貍便把大王給他的任務(wù),添上自己的考慮說了一遍。很快,他的朋友,用java寫出了一個(gè)程序,在大門的內(nèi)嵌電腦上運(yùn)行之。狐貍便對著那群飛蟲說:“蜜蜂們,蝴蝶們,你們好,歡迎你們來做客。今天人這么多,這么熱鬧,我們不如做個(gè)游戲。就是,當(dāng)我喊開始的時(shí)候,你們就從這個(gè)大門往里飛,一段時(shí)間,大門會自動關(guān)閉。然后,在大門里的,我們招待,在大門外的請便。”
          隨著狐貍的一聲開始,蜜蜂們,蝴蝶們就匆匆往里飛。大門關(guān)上之后,根據(jù)統(tǒng)計(jì)的蜜蜂、蝴蝶數(shù)量,擺桌開宴。

          宴畢,皆大歡喜,狐貍的朋友也得到兩瓶好酒。我聞聽此事,去訪狐貍的這位朋友,想看一下他的那個(gè)程序。他看了我一會,在鍵盤上調(diào)了一通,寫了一些代碼,要了我的U盤,保存到上面,遞給我說:“回去,好好看看這個(gè)。”
          回來后,我打開那個(gè)程序段,原來是有關(guān)線程優(yōu)先級問題的一個(gè)小程序:
          class Animal implements Runnable
          {
           int count=0;
           Thread t;
           private volatile boolean running=true;
           public Animal(int p)
           {
            t=new Thread(this);
            t.setPriority(p);
           }
           public void run()
           {
            while(running)
            {
             count++;
            }
           }
           public void stop()
           {
            running=false;
           }
           public void start()
           {
            t.start();
           }
          }
          public class Test
          {
           public static void main(String args[])
           {
            Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
            Animal bee=new Animal(Thread.NORM_PRIORITY+2);
            Animal butterfly=new Animal(4);
            bee.start();
            butterfly.start();
            try
            {
             Thread.sleep(50000);
            }
            catch (InterruptedException e)
            {
             System.out.println("Main thread interrupted.");
            }
            bee.stop();
            butterfly.stop();
            try
            {
             bee.t.join();
             butterfly.t.join();
            }
            catch (InterruptedException e)
            {
             System.out.println("InterruptedException caught");
            }
            System.out.println("關(guān)門>>>>>>");
            System.out.println("飛來蜜蜂"+bee.count+"只.");
            System.out.println("飛來蝴蝶"+butterfly.count+"只.");
           }
          }


          8、線程同步和死鎖
           當(dāng)兩個(gè)或更多線程需要訪問同一個(gè)共享資源時(shí),須用某種方式來確保資源某一時(shí)刻只被一個(gè)線程使用,達(dá)到這個(gè)目的方式稱之為同步。java中引入了互斥鎖的概念,每個(gè)對象都對應(yīng)于一個(gè)可稱為“互斥鎖”的標(biāo)記,這個(gè)標(biāo)記保證在任一時(shí)刻,只能有一個(gè)訪問該對象。關(guān)鍵字synchronized用來與對象的互斥鎖聯(lián)系,實(shí)現(xiàn)同步。凡有帶有synchronized關(guān)鍵字的方法或者代碼段,系統(tǒng)運(yùn)行時(shí)只會為之分配一個(gè)線程。
          實(shí)例:

          class TThread extends Thread
          {
           private int sum=0;
           String str=new String("");
           public void run()
           {
            while(true)
            {
             synchronized(str)
             {
              if(sum<=10)
              {
               try
               {
                Thread.sleep(10);
               }
               catch (Exception e)
               {
                e.printStackTrace();
               }
               System.out.println(Thread.currentThread().getName()+"now sum is:"+sum++);
              }
             }
            }
           }
          }
          public class Test
          {
           public static void main(String[] args)
           {
            TThread t=new TThread();
            Thread t1=new Thread(t);
            Thread t2=new Thread(t);
            Thread t3=new Thread(t);
            Thread t4=new Thread(t);

            t1.start();
            t2.start();
            t3.start();
            t4.start();
           }
          }

          注意: java語言中提供了wait()和notify()兩個(gè)方法,這兩個(gè)方法不能被重載,并且只能在同步方法中被調(diào)用。如果程序中有多個(gè)線程競爭多個(gè)資源,可能發(fā)生死鎖。當(dāng)一個(gè)線程等待由另一個(gè)線程持有的鎖,而后者正在等待已被第一個(gè)線程持有的鎖時(shí),就會發(fā)生死鎖。Java技術(shù)不檢測也不試圖避免這種情況,因而保證不發(fā)生死鎖是程序員的責(zé)任。一個(gè)通用的法則:決定獲取鎖的次序并始終遵照這個(gè)次序,按照與獲取相反的次序釋放鎖。

          Feedback

          # re: java基礎(chǔ):關(guān)于線程[未登錄]  回復(fù)  更多評論   

          2009-07-25 02:42 by ^_^
          帥!!!!!!!!!!!!!!!!!!!
          我喜歡
          主站蜘蛛池模板: 新民市| 信宜市| 麻阳| 嘉鱼县| 铜川市| 肃南| 栾城县| 靖远县| 新源县| 剑河县| 嵊州市| 普安县| 霍林郭勒市| 白银市| 综艺| 宣武区| 钟山县| 舞钢市| 巴塘县| 通山县| 合水县| 阿拉善右旗| 阜宁县| 平原县| 锦屏县| 石屏县| 罗定市| 安仁县| 厦门市| 星座| 浮梁县| 白城市| 深泽县| 仁化县| 红桥区| 广水市| 辽阳县| 五大连池市| 新源县| 延庆县| 蒙城县|