精品午夜福利中文字av_国产成人综合网_av毛片免费观看网站_欧美影视国产综合_野花香视频中文免费观看_亚洲无码要在线视频_又粗又大又用力大交换好大好爽小静_欧美贵妇v办公室高跟鞋_亚洲国产高清a∨网站_免费中文少妇亚洲

知ing

Java語言程序設計(第三版)

邵麗萍,邵光亞,張后揚 編 / 清華大學出版社

拼命菇涼@ 上傳

查看本書

10.1 多線程的概念
10.1.1 程序、進程和多任務
  程序:是對數據描述與操作的代碼的集合,是應用程序執(zhí)行的腳本
  進程:是程序的一次執(zhí)行過程,程序是靜態(tài)的,進程是動態(tài)的。系統(tǒng)運行一個程序就是一個進程從創(chuàng)建、運行到消亡的過程。
  多任務:一個系統(tǒng)中可以同時運行多個程序。一個CPU同時只能執(zhí)行一個程序的一條指令,多任務運行的并發(fā)機制使這些任務交替運行。
10.1.2 線程
  線程也稱為輕型進程(LWP),是比進程更小的運行單位,一個進程可以被劃分成多個線程。當一個程序執(zhí)行多線程時,可以運行兩個或多個由同一個程序啟動的任務。這樣一個程序可以使得多個活動任務同時發(fā)生。
10.1.3 多線程
  與進程不同的是,同類多線程共享一塊內存空間和一組系統(tǒng)資源,所以系統(tǒng)創(chuàng)建多線程開銷相對較小。
10.1.4 線程的生命同期與Java的多線程機制
  1.線程的生命同期與狀態(tài)
  線程有創(chuàng)建(New)、可運行(Runnable)、運行中(Running)、掛起(Not Runnable)、死亡(Dead)5種狀態(tài)。
  2.Java的多線程機制
  java.lang中的線程類Thread封裝了所有需要的線程操作控制,有很多方法用來控制一個線程的運行、休眠、掛起或停止。
10.2 創(chuàng)建線程
  建立一個線程需要完成三件事:
> 建立一個虛擬的CPU
> 給出線程的執(zhí)行代碼
> 提供代碼所操作的數據
  兩種方法可以創(chuàng)建線程:一種方法是通過繼承線程類Thread來創(chuàng)建線程類;另一種方法是建立一個實現(xiàn)Runnable接口的類一創(chuàng)建線程 。
10.2.1 通過繼承Thread類創(chuàng)建線程
  繼承Thread類這種方法中,需要覆蓋run( )方法來提供線程的執(zhí)行代碼,定義Thread類的成員變量來提供線程的數據。線程執(zhí)行時,從它的run( )方法中開始執(zhí)行,run()方法是線程執(zhí)行的起點
  例:public class SC extends Thread{
    int count=1,number;
    SC(int num){
    number=num;
    System.out.println("創(chuàng)建線程"+number);  }
    public void run(){
      while(true){
        System.out.println("線程"+number+":計數"+count);
        if(++count==3)   return;   }  }
    public static void main(String args[]){
     for (int i=0;i<3;i++)
        new SC(i+1).start();  } }
運行結果:創(chuàng)建線程1
     創(chuàng)建線程2
     創(chuàng)建線程3
     線程1:計數1
     線程1:計數2
     線程2:計數1
     線程2:計數2
     線程3:計數1
     線程3:計數2
例:P208
 public class SC extends Thread{
   public static void main(String args[]){
     testThread t1=new testThread("線程1");//僅是一空線程對象,沒有啟動這一線程,系統(tǒng)不為它分配資源,
     testThread t2=new testThread("線程2");
     t1.start();   t2.start(); } } //啟動線程
 class testThread extends Thread{
  public testThread(String str)
   {super(str);} //調用父類構造方法為線程對象命名
  public void run(){
     for (int i=0;i<3;i++){
     System.out.println(getName()+"在運行"); //getName返回線程名稱
     try
      {sleep(1000); //用休眠1000毫秒來區(qū)分哪個線程在運行
      System.out.println(getName()+"在休眠");}
    catch(InterruptedException e){} }
  System.out.println(getName()+"已結束");  }}
說明:由繼承Thread創(chuàng)建的子類,必須覆蓋run方法,因為run方法是abstact抽象方法
10.2.2 通過Runnable接口創(chuàng)建線程
  如果是Applet類應不能再繼承Thread類(不能多繼承),這時可以通過接口Runnable直接創(chuàng)建線程對象。接口中只聲明了一個未實現(xiàn)的run方法。
線程體的構造方法:
public Thread([ThreadGroup group][,Runnable target][,String name])
其中group指明該線程所屬的線程組,target是執(zhí)行線程體的目標對象,它必須實現(xiàn)接口Runnable,name則為線程名。這三個參數均可任意沒有。
任何實現(xiàn)接口Runnable的對象都可以作為一個線程的目標對象,類Thread本身也實現(xiàn)了接口Runnable,因此我們可以通過兩種方法實現(xiàn)線程體。
(1)定義一個線程類,它繼承類Thread并重寫其中的方法run(),這時在初始化這個類的實例時,目標對象target可為null
(2)提供一個實現(xiàn)接口Runnable類作為線程的目標對象,在初始化一個Thread類或者Thread子類的對象時,把目標對象傳遞給這個線程實例,由該目標對象提供線程體run()。這時實現(xiàn)接口Runnable的類仍然要以繼承其他父類。
例:P210
  import java.awt.*;
  import java.applet.Applet;
  import java.util.*;
  import java.text.DateFormat;
  public class SC extends Applet implements Runnable{
   Thread clockThread=null;
   public void init(){
    setBackground(Color.blue);
    setForeground(Color.yellow); }
   public void start(){
     if(clockThread==null){
       clockThread=new Thread(this,"Clock2");
    //Thread(ThreadGroup group,String name)name是線程名,group指定線程所屬的組
       clockThread.start();  } }
    public void run(){
     Thread myThread=Thread.currentThread();
   //找到當前執(zhí)行的線程,返回它的引用
     while(clockThread==myThread){
        repaint();
        try{ Thread.sleep(1000);
     }  catch(InterruptedException e){}
   } }
  
  public void paint(Graphics g){
    Date date=new Date();
    DateFormat formatter=DateFormat.getTimeInstance();
    String str=formatter.format(date);
    g.drawString(str,5,10); }
   public void stop()
    {clockThread=null;} }
10.2.3 可運行狀態(tài)(Runnable)
  Thread MyThread=new Thread()
  MyThread.start();
  這樣該線程處于可運行(Runnable)狀態(tài),注意,這狀態(tài)并不是運行中狀態(tài)(Running),因為線程也許實際并未真正運行(因很多計算機是單CPU)。當一個線程正在運行時,它是可運行的,并也是當前正運行的線程
10.2.4 不可運行狀態(tài)(Not Runnable)
  當下面四種情況發(fā)生時,線程就是進入不可運行狀態(tài):
(1)調用了sleep()方法
(2)調用了suspend()方法
(3)為等候一個條件變量,線程調用wait()方法
(4)輸入輸出流中發(fā)生線程阻塞
我們來看看下面這個例子:
  Thread myThread=new Thread();
  MyThread.start();
  try{   myThread.sleep(10000);}
  catch(InterrupedException e){
  }
  對于上面四種情況,都有特定的返回可運行狀態(tài)的方法與之對應,對應方法如下:
  (1)如果線程處于睡眠狀態(tài)中,sleep()方法中的參數為休息時間,當時間過去后,線程即為可運行的。
  (2)如果一線程被掛起,須由其他線程調用resume()方法來恢復該線程的執(zhí)行。
 ?。?)如果線程在等待條件變量,那么要停止等待的話,要該條件變量所在的對象調用notify(),notifyAll()方法。
  (4)如果在I/O流中發(fā)生線程阻塞,則特定的I/O指令將結束這種不可運行狀態(tài)
10.2.5 死亡狀態(tài)(Dead)
  一般可通過兩種方法實現(xiàn):自然撤消或是被停止
  1.自然撤消
  public void run(){
     int i=0;
     while(i<100){
     i++;
     System.out.println(“i=”+i);  }}
 當run()方法結束后,該線程應自然撤消了
  2.被停止
   Thread myThread=new Thread();
     MyThread.start();
   try{Trhead.currentThread().sleep(10000);
   } catch(InterruptedException e)
   myThread.stop();
10.2.6 非法狀態(tài)處理(IllegalThreadStateException)
  當一個線程剛被創(chuàng)建后,只能對它調用start()或stop()方法,若調用其他方法則會引起非法狀態(tài)處理。同樣對于任何狀態(tài),如果所調用的方法與狀態(tài)不符,都會引起非法狀態(tài)處理。
10.3  線程的優(yōu)先級
  Java為使有些線程可以提前得到服務,可給線程設置優(yōu)先級。在單個CPU上運行多線程時采用了線程隊列技術,Java虛擬機支持固定優(yōu)先級隊列,一個線程的執(zhí)行順序取決于其對其他Runnable線程的優(yōu)先級。優(yōu)先級分1~10同,默認級別是5級。
Thread的公用靜態(tài)常量表示:
  public static final int MAX_PRORITY=10 (最大優(yōu)先級10)
  public static final int MIN_PRORITY=1 (最小優(yōu)先級10)
  public static final int NORM_PRORITY=5 (默認優(yōu)先級5)
  
  public final int getPriority( ) //獲得線程優(yōu)先級
  public final setPriority(int newPriority) //設置線程優(yōu)先級
10.4  線程的調度與控制
10.4.1 線程類的方法
  1.線程的類方法
  Thread類的靜態(tài)方法,即可直接從Thread類調用
  CurrentThread( ):返回正在運行的Thread對象名稱
  sleep(int n):讓當前線程休眠n毫秒
  2.實例方法P213
10.4.2 控制線程的狀態(tài)
  1.掛起一個線程:suspend( )方法
  t.suspend():將t暫停執(zhí)行,必須由其他線程調用t.resume()恢復,不提倡使用該方法,因為容易造成死鎖
  2.停止一個線程:stop( )方法
  當線程完成運行并結束后,將不能再運行。另不可用t.stop()強行終止線程。注:這并沒有消滅這個線程,只是停止線程的執(zhí)行。但這個線程不能用t.start()重新啟動。不提倡采用這種方法,易造成線程的不一致。要通過設置flag通知一個線程應該結束。
  3.線程休眠:sleep(long )方法
  Thread.sleep()使一個線程暫停運行一段固定時間。
  4.連接線程:join( )方法
  t.join()使當前的線程等待,直到t結束為止,線程恢復到可運行狀態(tài)。三種調用格式:
  (1)join():如當前線程發(fā)出調用t.join(),則當前線程將等待線程t結束后再繼續(xù)執(zhí)行。
 ?。?)join(long millis):如當前線程發(fā)出調用t.join(long millis),則當前線程將等待線程t結束或最多等待mills毫秒后再繼續(xù)執(zhí)行。
 ?。?)join(long millis,int nanos):如當前線程發(fā)出調用t.join(long millis,int nanos),則當前線程將等待線程t結束或最多等待mills毫秒+nanos納秒后再繼續(xù)執(zhí)行。
  5.暫停(退讓)線程:yield( )方法(只讓給同優(yōu)先級運行)
  調用t.yield()方法可暫停當前運行線程,但處于可運行狀態(tài),讓同優(yōu)先級線程先運行。若沒有同等優(yōu)先級的線程是可運行狀態(tài),yield方法將什么也不做。
  6.中斷線程:interrupt( )方法
  如果一個線程t在調用sleep(),join(),wait()方法被阻塞時,則t.interrupt()方法將使t的中斷狀態(tài)被清除,中斷t的阻塞狀態(tài),并且將接收到InterruptException異常。
  一個線程可以通過獲取另一個線程的引用,調用該線程的interrupt()方法來中斷另一個sleep或wait線程的執(zhí)行
  7.了解線程的狀態(tài):isAlive( )方法
  返回true則線程處于Runnable或Not Runnable狀態(tài)(即已啟動但還沒有運行結束),返回false則說明線程處于New Thread或Dead狀態(tài)
  
   
    start()         調度
     
                    時間片到y(tǒng)ield()             run(),stop()結束
  
        時間到     sleep()
        interrupt()  join()       wait()
              synchronized()
                 獲得互斥
                   使用權       
  
              notify()
             notifyall()
           線程狀態(tài)的轉換圖
  
  例:public class SC{
  public static void main(String args[]) throws Exception{
    int i=0;
    Hello t=new Hello();
    t.start();
    while(true){
      System.out.println("早上好!"+i++);
      if (i==2&&t.isAlive()){
          System.out.println("Main waiting for Hello!");
          t.join(); //等待t運行結束 
    }
      if (i==4) break;   }}}
  class Hello extends Thread{
    int i;
    public void run(){
     while (true){
     System.out.println("嗨"+i++);
     if(i==4) break; } } }
  運行結果:
    早上好!0
    早上好!1
    Main waiting for Hello!
    嗨0
    嗨1
    嗨2
    嗨3
    早上好!2
    早上好!3
10.5  線程的同步機制與共享資源(自學)

查看更多