Picses' sky

          Picses' sky
          posts - 43, comments - 29, trackbacks - 0, articles - 24

          java線程簡單介紹[zz]

          Posted on 2007-07-18 10:55 Matthew Chen 閱讀(684) 評論(2)  編輯  收藏 所屬分類: Java MultiThread

          在java中,一個線程用一個Thread對象表示
          一般每一個java程序都有一個main方法(applet沒有),它是主線程的入口點
          而用Thread表示的線程,入口點自然不是main了,而是run方法
          定義一個線程,主要就是寫它的run方法
          寫run有兩種方法,一種是繼承Thread類,然后重寫它的run
          另一種是實現Runnable接口,然后重寫它的run,如下所示:
          ============================
          //用外部類實現多線程
          class  ThreadTest2
          {
           public static void main(String[] args)
           {
            new ThreadTest2();
           }
           ThreadTest2(){
            for(int i=1; i<=5; i++){
             System.out.println("creating thread "+i);
             outterThread th = new outterThread(i);//創建新線程
             th.start();//啟動剛創建的線程
            }
           }
          }

          class outterThread extends Thread//通過繼承Thread類來實現多線程;外部類
          {
           int count;
           outterThread(int i){
            count = i;
           }
           public void run() {
            while(true){
             System.out.println("thread "+count+" is running");
             try{
              sleep(1000*count);
             }
             catch(InterruptedException e){}
            }
           }
          }
          =====================================
          class ThreadTest3 implements Runnable //通過實現Runnable接口來實現多線程
          {
           int count;
           public static void main(String[] args)
           {
            for(int i=1; i<=5; i++)
             //調用了Thread類的構造函數Thread(Runnable target)
             new Thread(new ThreadTest3(i)).start();
           }
           ThreadTest3(int i){
            System.out.println("creating thread "+i);
            count = i;
           }
           public void run(){
            while(true){
             System.out.println("thread "+count+" is running");
             try{
              Thread.sleep(1000*count);//讓線程睡眠一段時間
             }
             catch(InterruptedException e){}
            }
           }
          }
          可以看到,不論如何重寫run,都要生成Thread對象.不同的是,第二種方法要在Thread的構造函數里傳入Runnable的實現類作為參數
          上面的例子還用到了start()和sleep()
          前者用作啟動線程,調用它之后,run方法就開始執行;后者使線程暫停參數指定的時間,單位是毫秒.這個sleep會拋出異常,所以要有try,catch塊
          ===========================
          在上面的例子中,在for循環中創建的線程和主線程是并列的,一個線程的結束不會影響另一個線程
          在上面的例子中,執行完for循環,主線程就結束了,而其他線程還在運行著
          用setDaemon()可以使一個線程作為后臺線程執行,也就是說,當其他非Daemon線程結束時,不論run執行完沒有,后臺線程也將退出
          反過來,你也可以使主線程等待其他線程結束后再退出.注意這里是主線程等待其他線程結束,而上面講的daemon線程是在所有非daemon(主線程和其他非daemon)退出后再退出.要實現這一目的,可使用join().它可帶可不帶參數,帶參數的話, 參數表示等待時間,如果過了這指定的時間不管join了的線程退出與否,主線程都會結束(如果main方法已經執行完了)
          下面是例子
          =======================
          class DaemonAndJoin
          {
           public static void main(String[] args)
           {
            Thread th = new Thread( new Runnable(){ 
             int count = 2;
             public void run(){
              while(count>0){
               for(int i=0; i<5; i++){
                try{
                 Thread.sleep(500);
                 System.out.println("in thread 1 ");
                }catch(InterruptedException e){
                 e.printStackTrace();
                }
               }
               count--;
               System.out.println("one for is done");
              }
             }
            });
            Thread th2 = new Thread(new Runnable(){
             public void run(){
              while(true){
               try{
                Thread.sleep(1000);
                System.out.println("in thread 2");
               }catch(InterruptedException e){
                e.printStackTrace();
               }
              }
             }
            });
            System.out.println("main thread begins");  
            th.start(); 
            th2.setDaemon(true);//設置后臺線程
            th2.start();
            try{
             th.join();//join
            }catch(InterruptedException e){
             e.printStackTrace();
            }
            System.out.println("main thread quits");
           }
          }
          ==============
          上面例子,如果沒有th這個線程,th2和主線程都會很快結束
          如果有th,但是沒有join,主線程會很快結束,但是th2因為還有一個非daemon未結束,所以不會很快結束,而一直等到th結束才結束
          如果沒有setDaemon,則th不影響th2
          ==================
          線程的同步
          當多個線程同時對一個對象進行操作,就有可能發生問題,這時就要用線程同步來解決
          考慮下面的例子
          class SychronizedTest
          {
           public static void main(String[] args)
           {
            final Student stu = new Student();
            Thread setNameAndNumth1 = new Thread( new Runnable(){
             public void run(){
              while(true){
               synchronized(stu){
                stu.setNameAndNum("john","jj");
               }
              }
             }
            });
            Thread setNameAndNumth2 = new Thread( new Runnable(){
             public void run(){
              while(true){
               //synchronized(stu){
                stu.setNameAndNum("kate","kk");
               //}
              }
             }
            });
            setNameAndNumth1.start();
            setNameAndNumth2.start();
            System.out.println("test started:");
           }
          }
          class Student{
           private String name;
           private String id;
           private int count = 0;
           public /*synchronized*/ void setNameAndNum(String name,String id){
          //  synchronized(this){
             this.name = name;
             this.id = id;
             count++;
             if(!check())
              System.out.println( count + " unmatched name and id: "+name+" "+id);
          //  }
           }
           private boolean check(){
            return name.charAt(0) == id.charAt(0);
           }
          }
          在這個例子中,Student類有兩個屬性.
          有兩個線程,它們修改同一個Student類的實例,然后檢查修改后的這個實例的兩個屬性符不符合要求(判斷兩個屬性的第一個字符是否一樣)
          如果不符合要求,則在控制臺輸出語句,否則不輸出
          例子中有三部分注釋,每一部分說明了一種同步方式
          最上面方式使Student類的方法都按同步的方式執行
          第二種通過synchronized關鍵字,使單一一個方法,而不是全部方法按同步的方式執行
          第三種只是一個方法里的某一部分按同步的方法執行(雖然在這個例子里,方法的整個方法體都被括起來了)
          ====================================
          最后附上經典的生者消費者程序
          class WaitNotifyTest
          {
           public static void main(String[] args)
           {
            Clerk clerk = new Clerk();
            Producer producer = new Producer(clerk);
            Consumer consumer = new Consumer(clerk);
            Thread producerThread = new Thread(producer);
            Thread consumerThread = new Thread(consumer);
            producerThread.start();
            consumerThread.start();
           }
          }
          class Producer implements Runnable{
           Clerk clerk;
           Producer(Clerk clerk){
            this.clerk = clerk;
           }
           public void run(){
            System.out.println("producer starts producing product " );
            for(int i=0; i<10; i++){
             try{
              Thread.sleep( (int)(Math.random()*3000) );
             }catch(InterruptedException e){
              e.printStackTrace();
             }
             clerk.setProduct(i);
          //   System.out.println("producer is producing product " + i);
             
            }
           }
          }
          class Consumer implements Runnable{
           Clerk clerk;
           Consumer(Clerk clerk){
            this.clerk = clerk;
           }
           public void run(){
            System.out.println("consumer starts consuming product " );
            for(int i=0; i<10; i++){
             try{
              Thread.sleep( (int)(Math.random()*3000) );
             }catch(InterruptedException e){
              e.printStackTrace();
             }
             clerk.getProduct();
          //   System.out.println("consumer is consuming product "+ i);
             
            }
           }
          }
          class Clerk{
           int product = -1;
           public synchronized void setProduct(int product){
            if( this.product != -1  ){
             try{  
               wait();
              }catch(InterruptedException e){
               e.printStackTrace();
              }
            }
            this.product = product;
            System.out.println("producer is producing product " + product);
            notify();
           }
           public synchronized void getProduct(){
            if( product == -1 ){
             try{
              wait();
             }catch(InterruptedException e){
              e.printStackTrace();
             }
            }
            System.out.println("consumer is consuming product "+ product);
            this.product = -1;
            notify();
           }

          Feedback

          # re: java線程簡單介紹[zz]  回復  更多評論   

          2009-04-09 20:56 by huxianbao
          太有用了,呵呵

          # re: java線程簡單介紹[zz]  回復  更多評論   

          2009-04-09 22:56 by huxianbao
          最后一個生產者-消費者程序真的是太經典了
          呵呵
          主站蜘蛛池模板: 娄烦县| 石楼县| 玉龙| 南康市| 铜陵市| 竹山县| 和林格尔县| 大洼县| 大关县| 海兴县| 商丘市| 江达县| 仙居县| 巴南区| 垫江县| 永靖县| 新泰市| 宜都市| 凤阳县| 梅州市| 利津县| 南宁市| 曲阜市| 紫云| 云阳县| 钦州市| 莲花县| 南宁市| 逊克县| 苗栗市| 林州市| 玉田县| 蕲春县| 高清| 彭州市| 新竹市| 包头市| 佛冈县| 八宿县| 芮城县| 光山县|