無線&移動互聯網技術研發

          換位思考·····
          posts - 19, comments - 53, trackbacks - 0, articles - 283
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          多線程實用操作方法大全

          Posted on 2009-07-19 23:41 Gavin.lee 閱讀(856) 評論(0)  編輯  收藏 所屬分類: 多線程

           線程控制基本方法
            方    法                             功    能
          isAlive()                     判斷線程是否還“活”著,即當前run線程是否還未終止。
          getPriority()               獲得線程的優先級數值
          setPriority()               設置線程的優先級數值
          Thread.sleep()           將當前線程睡眠指定毫秒數
          join()                         調用某線程的該方法,將當前線程與該線程“合并”,即等待該線程結束,再恢復當前線程的運行。
          yield()                       讓出CPU,當前線程進入就緒隊列等待調度。
          wait()                       當前線程進入對象的wait pool。
          notify()/notifyAll()      喚醒對象的wait pool中的一個/所有等待線程。

          run()和start()

          這兩個方法應該都比較熟悉,把需要并行處理的代碼放在run()方法中,start()方法啟動線程將自動調用 run()方法,這是由Java的內存機制規定的。并且run()方法必須是public訪問權限,返回值類型為void。

          isAlive方法實例:

          package com.Gavin.createthread;

          public class TestIsAlive {

              
          public static void main(String[] args) {
                  Thread6 t6 
          = new Thread6("t6");
                  t6.start();
                  
                  
          for(int i = 0; i < 50; i++{
          //            System.out.println(Thread.currentThread().getName());    //主線程
                      System.out.println("t6's name:" + t6.getName());
                  }

              }


          }


          class Thread6 extends Thread {
              
          public Thread6(String string) {
                  
          super(string);
              }

              
          public void run() {
                  System.out.println(
          "thread is alive:" + Thread.currentThread().isAlive());
                  
                  
          for(int i = 0; i < 50; i++{
                      System.out.println(
          "subThread:" + i);
                  }

              }

          }


          interrupt/sleep方法:
                      可以調用Thread的靜態方法: public static void sleep(long millis) throws InterruptedException
                          使得當前線程休眠(暫時停止執行millis毫秒)。
                      由于是靜態方法,sleep可以由類名直接調用:Thread.sleep(…)

          使當前線程(即調用該方法的線程)暫停執行一段時間,讓其他線程有機會繼續執行,但它并不釋放對象鎖。也就是如果有Synchronized同步塊,其他線程仍然不同訪問共享數據。注意該方法要捕獲異常

          比如有兩個線程同時執行(沒有Synchronized),一個線程優先級為MAX_PRIORITY,另一個為MIN_PRIORITY,如果沒有 Sleep()方法,只有高優先級的線程執行完成后,低優先級的線程才能執行;但當高優先級的線程sleep(5000)后,低優先級就有機會執行了。

          總之,sleep()可以使低優先級的線程得到執行的機會,當然也可以讓同優先級、高優先級的線程有執行的機會。

          package com.Gavin.createthread;

          import java.util.Date;

          public class TestInterrupt {    
              
          public static void main(String[] args) {
                  Thread1 t 
          = new Thread1();
                  t.start();
                  
          /**
                   * api中稱:中斷線程
                   * Thread1線程與主線程開始并發,主線程讓出10s,
                   * 然后調用interrupt強行終止Thread1線程
                   
          */

                  
          try {
                      Thread.sleep(
          10000);
                  }
           catch(InterruptedException e) {            
                  }

                  
                  t.interrupt();
              }

          }


          class Thread1 extends Thread {
              
          public void run() {
                  
          while (true{
                      System.out.println(
          "===" + new Date()+ "===");
                      
          try {
                          sleep(
          1000);
                      }
           catch (InterruptedException e) {
                          
          return;
                      }

                  }

              }

          }

          停止線程的方法中,stop最強暴,其次便是interrupte,這兩種都是不提倡的,推薦的方法是通過flag標志來終止線程,例如:

          package com.Gavin.createthread;
          public class TestShutDown {    
              
          public static void main(String[] args) {    
                  Thread5 t5 
          = new Thread5();
                  Thread t 
          = new Thread(t5);
                  t.start();        
                  
          for(int i = 0; i < 100; i++{
                      System.out.println(
          "main thread i:" + i);
                  }

                  System.out.println(
          "main thread is over");
                  
          /**
                   * 通過操作flag標志來關閉線程,推薦使用
                   
          */

                  t5.shutDown();        
          //        t.stop();    //太暴力,不推薦
              }

          }

          class Thread5 implements Runnable {
              
          private boolean flag = true;    
              
          public void run() {
                  
          int i = 0;
                  
          while(flag) {
                      System.out.println(
          "value:" + i++);
                  }
                  
              }
              
              
          public void shutDown() {
                  flag 
          = false;
              }

          }



          join方法:
                      合并某個線程,,join()方法使調用該方法的線程在此之前執行完畢,也就是等待調用該方法的線程執行完畢后再往下繼續執行。注意該方法也要捕獲異常。

          package com.Gavin.createthread;

          public class TestJoin {
              
          public static void main(String[] args) {
                  
          //指定新的線程對象,并通過super指向Thread,指定線程名稱
                  Thread2 t = new Thread2("Thread2 ");        
                  t.start();
                  
          /**
                   * api中稱:等待該線程終止。
                   * 當線程啟動后,原本線程是會與主線程并發執行
                   * 當調用了join方法后,意味著Thread2線程將會與主線程合并
                   * 所以,需要等待Thread2線程執行完畢,合并后,主線程才會繼續執行
                   
          */

                  
          try {
                      t.join();
                  }
           catch (InterruptedException e) {
                  }

                  
          for(int i = 0; i <= 10; i++{
                      System.out.println(
          "i am main thread " + i);
                  }

              }

          }


          class Thread2 extends Thread {
              Thread2(String string) 
          {
                  
          super(string);
              }
              
              
          public void run() {
                  
          for(int i = 0; i <= 10; i++{
                      System.out.println(
          "i am " + getName() + i);
                      
          try {
                          
          /**
                           * api中稱:在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行),
                           * 此操作受到系統計時器和調度程序精度和準確性的影響 
                           
          */

                          sleep(
          1000);
                      }
           catch (InterruptedException e) {
                          
          return;
                      }

                  }

              }
              
          }

          yield方法:
                      暫時讓出CPU,給其他線程執行的機會,它與sleep()類似,只是不能由用戶指定暫停多長時間,并且yield()方法只能讓同優先級的線程有執行的機會。

          package com.Gavin.createthread;

          public class TestYield {
              
          public static void main(String[] args) {
                  Thread3 t 
          = new Thread3("t");
                  Thread3 tt 
          = new Thread3("tt");
                  t.start();
                  tt.start();
              }

          }

          class Thread3 extends Thread {
              Thread3(String string) 
          {
                  
          super(string);
              }

              
          public void run () {
                  
          for(int i = 0; i < 100; i++{
                      System.out.println(getName() 
          + ":" + i);
                      
          if(i % 10 == 0{
                          
          /**
                           * api中稱:暫停當前正在執行的線程對象,并執行其他線程。
                           * 注:暫停時間片不定,只是到條件即暫時讓出cpu
                           
          */

                          yield();
                      }

                  }

              }

          }


          setPriority():

          package com.Gavin.createthread;

          public class TestPriority {

              
          public static void main(String[] args) {
                  Thread t1 
          = new Thread(new T1());
                  Thread t2 
          = new Thread(new T2());
                  
          /**
                   * 未設置優先級的,t1,t2將幾乎擁有均等的時間片,交互執行
                   * 但是當設置優先級后,t1會擁有更長時間片。甚至t1在搶奪的時間片內已執行完。
                   
          */

                  t1.setPriority(Thread.NORM_PRIORITY 
          + 3);
                  
                  t1.start();
                  t2.start();
              }


          }


          class T1 implements Runnable {
              
          public void run() {
                  
          for(int i = 0; i < 200; i++{
                      System.out.println(
          "T1:" + i);
                  }

              }
              
          }
           

          class T2 implements Runnable {
              
          public void run() {
                  
          for(int i = 0; i < 200; i++{
                      System.out.println(
          "T2:" + i);
                  }

              }

              
          }

           


          關鍵字Synchronized

          這個關鍵字用于保護共享數據,當然前提是要分清哪些數據是共享數據。每個對象都有一個鎖標志,當一個線程訪問該對象時,被Synchronized修飾的數據將被“上鎖”,阻止其他線程訪問。當前線程訪問完這部分數據后釋放鎖標志,其他線程就可以訪問了。
           

          //同步鎖
          public class TestSync implements Runnable {
              Timer timer 
          = new Timer();    
              
          public static void main(String[] args) {
                  TestSync test 
          = new TestSync();
                  Thread t1 
          = new Thread(test);
                  Thread t2 
          = new Thread(test);

                  
          //t1.setName("t1");
                  
          //t2.setName("t2");
                  t1.start();
                  t2.start();
              }

              
          public void run() {
                  timer.add(Thread.currentThread().getName());
              }

          }

          class Timer{
              
          private static int num = 0;

              
          //synchronized 鎖定當前對象
              public synchronized void add(String name) {
                  
          //synchronized(this) {
                      num++;
                      
          try    {
                          Thread.sleep(
          1);
                      }
           catch (InterruptedException e){

                      }

                      System.out.println(name 
          + ",你是第" + num + "個使用timer的線程");
                  
          //}
              }

          }

           

          注意以下這個例子

          public ThreadTest implements Runnable 
              
          public synchronized void run()
                  
          for(int i=0;i<10;i++
                  System.out.println(
          " " + i); 
                  }
           
              }
           
              
          public static void main(String[] args) 
                  Runnable r1 
          = new ThreadTest(); 
                  Runnable r2 
          = new ThreadTest(); 
                  Thread t1 
          = new Thread(r1); 
                  Thread t2 
          = new Thread(r2); 
                  t1.start(); 
                  t2.start(); 
              }

          }

          結果: 0 0 1 2 3 4 1 5 2 6 3 7 4 8 9 5 6 7 8 9 ;(不同對象)
          以上這段程序中的 i 變量并不是共享數據,這個程序中的t1,t2分別是兩個對象(r1,r2)的線程。JAVA是面向對象的程序設計語言,不同的對象的數據是不同的,r1,r2有各自的run()方法,而synchronized使同一個對象的多個線程,在某個時刻只有其中的一個線程可以訪問這個對象的synchronized數據。

          當把代碼改成如下:Synchronized關鍵字才會起作用

          Runnable r = new ThreadTest();

          Thread t1 = new Thread(r);

          Thread t2 = new Thread(r);

          t1.start();

          t2.start();

          synchronized 導致的死鎖問題:


          //死鎖典型:哲學家吃飯問題
          public class TestDeadLock implements Runnable{
              
          public int flag = 1;
              
          static Object o1 = new Object();
              
          static Object o2 = new Object();
              
          public void run() {
                  System.out.println(
          "flag=" + flag);
                  
          if(flag == 1{
                      
          synchronized(o1) {
                          
          try    {
                              Thread.sleep(
          500);
                          }
          catch (InterruptedException e)    {
                              e.printStackTrace();
                          }

                          
          synchronized(o2) {
                              System.out.println(
          "1");
                          }

                      }

                  }


                  
          if(flag == 0{
                      
          synchronized(o2) {
                          
          try    {
                              Thread.sleep(
          500);
                          }
          catch (InterruptedException e)    {
                              e.printStackTrace();
                          }

                          
          synchronized(o1) {
                              System.out.println(
          "0");
                          }


                      }

                  }
              
              }


              
          public static void main(String[] args) {
                  TestDeadLock td1 
          = new TestDeadLock();
                  TestDeadLock td2 
          = new TestDeadLock();
                  td1.flag 
          = 1;
                  td2.flag 
          = 0;
                  Thread t1 
          = new Thread(td1);
                  Thread t2 
          = new Thread(td2);
                  t1.start();
                  t2.start();
              }

          }



          wait()和notify()、notifyAll()

          這三個方法用于協調多個線程對共享數據的存取,所以必須在Synchronized語句塊內使用這三個方法。前面說過Synchronized這個關鍵字用于保護共享數據,阻止其他線程對共享數據的存取。但是這樣程序的流程就很不靈活了,如何才能在當前線程還沒退出Synchronized數據塊時讓其他線程也有機會訪問共享數據呢?此時就用這三個方法來靈活控制。

          wait()方法使當前線程暫停執行并釋放對象鎖標志,讓其他線程可以進入Synchronized數據塊,當前線程被放入對象等待池中。當調用 notify()方法后,將從對象的等待池中移走一個任意的線程并放到鎖標志等待池中,只有

          鎖標志等待池中的線程能夠獲取鎖標志;如果鎖標志等待池中沒有線程,則notify()不起作用。

          notifyAll()則從對象等待池中移走所有等待那個對象的線程并放到鎖標志等待池中。

          注意 這三個方法都是java.lang.Ojbect的方法!

          主站蜘蛛池模板: 定远县| 陆川县| 武邑县| 乾安县| 清水县| 银川市| 衡水市| 沭阳县| 海阳市| 慈利县| 惠来县| 仙桃市| 柯坪县| 米泉市| 定结县| 屏山县| 孟津县| 会泽县| 郎溪县| 柳河县| 曲麻莱县| 金昌市| 宜昌市| 买车| 若尔盖县| 安福县| 白银市| 荆门市| 平罗县| 江西省| 合作市| 金寨县| 崇阳县| 新源县| 晋中市| 花莲市| 怀柔区| 平顺县| 新巴尔虎右旗| 安岳县| 苍溪县|