国产最新a级毛片无码专区_综合亚洲欧美日韩久久精品_日本成年片在线观看66_一本到九九av电影_一级毛片免费网站播放_国内精品久久人无码大片_国产人成视频99在线观看_欧美不卡在线一本二本_国产亚洲电影av_可以免费看黄色软件

知ing

Java語(yǔ)言程序設(shè)計(jì)(第三版)

邵麗萍,邵光亞,張后揚(yáng) 編 / 清華大學(xué)出版社

拼命菇?jīng)鯜 上傳

查看本書

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

查看更多