第一章



    ??????

5.13  动  态  成  员  函  数  发  送  

当  你  用  点  操  作  符  调  用  一  个  对  象  实  例  的  成  员  函  数  时,  对  象  实  例  所  属  的  类  在  编  译  时  要  被  检  查,  以  确  保  调  用  的  成  员  函  数  在  该  类  中  是  存  在  的。  在  运  行  时,  对  象  实  例  可  以  指  向  所  声  明  类  型  的  子  类  的  实  例。  在  这  ?copy;  情  况  下,  如  果  子  类  覆  盖  了  要  调  用  的  成  员  函  数,Java就  用  实  例  来  决  定  调  用  哪  一  个  成  员  函  数。  如  下  面  的  例  子,  两  个  类  是  子  类  和  超  类  的  关  系,  子  类  覆  盖  了  超  类  的  成  员  函  数。  

class  A  {  void  callme(  )  {  System.out.println(\"在A的callme成  员  函  数  里\");  }  }  

class  B  extends  A  {  void  callme(  )  {  System.out.println(\"在B的callme成  员  函  数  里\");  }  }  

class  Dispatch  {  public  static  void  main(String  args[])  {  A  a  =  new  B(  );  a.callme(  );  }  }  

有  趣  的  是,  在  成  员  函  数main里,  我  们  把  变  量a声  明  为  类  型A,  然  后  把  类B的  一  个  实  例  存  放  到  它  上  面。  我  们  在a上  调  用  成  员  函  数callme,Java编  译  器  确  定  在  类A确  实  有  成  员  函  数callme,  但  是  在  运  行  时,  由  于a事  实  上  是B的  实  例,  所  以  调  用B的callme,  而  不  调  用A的。  下  面  是  运  行  结  果:  C:\\>java  Dispatch  在B的callme成  员  函  数  里  

5.14  final  

在  缺  省  情  况  下,  所  有  的  成  员  函  数  和  实  例  变  量  都  可  以  被  覆  盖。  如  果  你  希  望  你  的  变  量  或  成  员  函  数  不  再  被  子  类  覆  盖,  可  以  把  它  们  声  明  为final。  这  意  味  着  将  来  的  实  例  都  依  赖  这  个  定  义。  例  如:  final  int  FILE_NEW  =  1;  final  int  FILE_OPEN  =  2;  final  int  FILE_SAVE  =  3;  fianl  int  FILE_SAVEAS  =  4;  final  int  FILE_QUIT  =  5;  final变  量  用  大  写  标  识  符  是  一  个  一  般  的  约  定。  

5.15  静  态  

如  果  你  想  要  创  建  一  个  可  以  在  实  例  的  外  部  调  用  的  成  员  函  数,  那  么  你  只  需  声  明  它  为  静  态  的  (static?copy;,  它  就  会  正  常  运  行。  静  态  成  员  函  数  只  能  直  接  调  用  其  他  静  态  成  员  函  数,  而  不  能  以  任  何  方  式  使  用this或super。  你  也  可  以  把  变  量  声  明  为  静  态  的。  如  果  你  想  初  始  化  一  个  静  态  变  量,  你  可  以  用  static声  明  一  个  恰  好  在  类  调  用  时  执  行  一  次  的  程  序  块。  下  面  的  例  子  是  一  个  带  有  一  个  静  态  成  员  函  数,  几  个  静  态  变  

量,  和  一  个  静  态  初  始  块  的  类。  

class  Static  {  static  int  a  =  3;  static  int  b;  static  void  method(int  x){  System.out.println(\"x  =  \"  +  x);  System.out.println(\"a  =  \"  +  a);  System.out.println(\"b  =  \"  +  b);  }  static  {  System.out.println(\"静  态  初  始  块\");  b  =  a  *  4;  }  public  static  void  main(String  args[])  {  method(42);  }  }  这  个  类  被  调  用,  所  有  的  静  态  变  量  都  被  初  始  化,a被  赋  为3,  然  后  运  行static块,  这  将  打  印  出  一  段  消  息,  并  且  把b赋  为a*4,  即12。  然  后  解  释  器  调  用main成  员  函  数,  它  调  用  了  成  员  函  数  method,  参  数x为42。  这  三  个println语  句  打  印  了  两  个  静  态  变  量a、b和  局  部  变  量x。  下  面  是  运  行  结  果:  C:\\>java  Static  静  态  初  始  块  x  =  42  a  =  3  b  =  12  一  个  静  态  成  员  函  数  可  以  通  过  它  所  属  的  类  名  来  调  用。  象  调  用  实  例  变  量  一  样,  你  可  以  用  点  操  作  符  通  过  类  名  来  调  用  静  态  成  员  函  数  和  静  态  变  量。Java就  是  这  样  实  现  了  全  局  函  数  和  全  局  变  量。  下  面  的  例  子  里,  我  们  创  建  了  带  有  一  个  静  态  成  员  函  数  和  两  个  静  态  变  量  的  类。  第  二  个  类  可  以  通  过  名  字  直  接  来  调  用  第  一  个  类  的  静  态  成  员  函  数  和  静  态  变  量。  

class  staticClass  {  static  int  a  =  42;  static  int  b  =  99;  static  void  

callme(  )  {  System.out.println(\"a  =  \"  +  a);  }  }  

class  StaticByName  {  public  static  void  main(String  args[])  

{  StaticClass.callme(  );  System.out.println(\"b  =  \"  +  staticClass.b);  }  }  

下  面  是  运  行  结  果:  C:\\>java  staticByName  a  =  42  b  =  99  

5.16  抽  象  

有  时  你  需  要  定  义  一  个  给  出  抽  象  结  构、  但  不  给  出  每  个  成  员  函  数  的  完  整  实  现  的  类。  如  果  某  个  成  员  函  数  没  有  完  整  实  现,  必  须  要  由  子  类  来  覆  盖,  你  可  把  它  声  明  为  抽  象(abstract?copy;  型。  含  有  抽  象  型  成  员  函  数  的  类  必  须  声  明  为  抽  象  的。  为  了  把  一  个  类  声  明  为  抽  象  的,  你  只  需  在  类  定  义  的class关  键  词  前  放  置  关  键  词abstract。  这  ?copy;  类  不  能  直  接  用new操  作  符  生  成  实  例,  因  为  它  们  的  完  整  实  现  还  没  有  定  义。  你  不  能  定  义  抽  象  的  构  造  函  数  或  抽  象  的  静  态  成  员  函  数。  抽  象  类  的  子  类  或  者  实  现  了  它  的  超  类  的  所  有  抽  象  的  成  员  函  数,  或  者  也  被  声  明  为  抽  象  的。  下  面  例  子  是  一  个  带  有  抽  象  成  员  函  数  的  类,  其  后  是  一  个  实  现  了  该  成  员  函  数  的  类。  

abstract  class  A  {  abstract  void  callme(  )  ;  void  metoo(  )  {  system.out.println(\"在A的metoo成  员  函  数  里\");  }  }  class  B  extends  A  {  void  callme(  )  {  System.out.println(\"在B的callme成  员  函  数  里\");  }  }  class  Abstract  {  public  static  void  main(String  args[])  {  A  a  =  new  B(  );  

a.callme(  );  a.metoo(  );  }  }  

下  面  是  运  行  结  果:  C:\\>java  Abstract  在B的callme成  员  函  数  里  在A的metoo成  员  函  数  里  

本  章  小  结  

1.  类  是Java语  言  面  向  对  象  编  程  的  基  本  元  素,  它  定  义  了  一  个  对  象  的  结  构  和  功  能。  2.  Java通  过  在  类  定  义  的  大  括  号  里  声  明  变  量  来  把  数  据  封  装  在  一  个  类  里,  这  里  的  变  量  称  为  实  例  变  量。  3.  成  员  函  数,  是  类  的  功  能  接  口,  是  类  定  义  里  的  一  个  子  程  序,  在  类  的  定  义  里  和  实  例  变  量  处  于  同  一  级  别。

第  六  章  Java图  形  用  户  接  口  

对  一  个  优  秀  的  应  用  程  序  来  说,  良  好  的  图  形  用  户  接  口  是  必  不  可  少  的。  缺  少  良  好  的  图  形  用  户  接  口,  将  会  给  用  户  理  解  和  使  用  应  用  程  序  带  来  很  多  不  便。  很  难  想  象  用  户  为  了  学  会  使  用  一  个  应  用  程  序,  去  记  一  大  堆  命  令。  Java提copy;  了  生  成  一  个  良  好  的  图  形  用  户  接  口  所  需  要  的  一copy;  基  本  元  件:  面  板(Panel  copy;、  按  钮  (Button  copy;、  标copy;(Label  copy;、  画  板(Canvases  copy;、  滚  动  条(Scrollbar  copy;、  列  表  框(List  copy;、  文  本  域(Text  Field  copy;、  文  本  区(Text  Area  copy;。  

6.1  面  板  

面  板  提copy;  了  建  立  应  用  程  序  的  空  间。  你  可  以  把  图  形  元  件(包  括  其  他  面  板  copy;  放  在  一  个  面  板  上。  Applet类  提copy;  了  一  个  基  本  的  面  板。  

6.1.1  布  局  管  理  

Java提copy;  了  几  种  布  局:  顺  序  布  局(Flow  Layout  copy;、  边  界  布  局(Border  Layout  copy;  和  网  格  布  局  (Grid  Layout)

6.1.1.1  顺  序  布  局  

顺  序  布  局(Flow  Layout  copy;  是  最  基  本  的  一  种  布  局,  面  板  的  缺  省  布  局  就  是  顺  序  布  局。  顺  序  布  局  指  的  是  把  图  形  元  件  一  个  接  一  个  地reg;  平  地  放  在  面  板  上。  下  面  是  一  个  顺  序  布  局  的  例  子:  

import  java.awt.*;  import  java.applet.Applet;  

public  class  myButtons  extends  Applet  {  Button  button1,  button2,  button3;  

public  void  init()  {  button1  =  new  Button(\"确  定\");  button2  =  new  Button(\"打  开\");  button3  =  new  Button(\"关  闭\");  add(button1);  add(button2);  add(button3);  }  }  

6.1.1.2  边  界  布  局  

边  界  布  局  包  括  五  个  区:  北  区、  南  区、  东  区、  西  区  和  中  区。  这  几  个  区  在  面  板  上  的  分  布  规  律  是\"  上  北  下  南,  左  西  右  东\"。  下  面  是  一  个  边  界  布  局  的  例  子:  

import  java.awt.*;  import  java.applet.Applet;  

public  class  buttonDir  extends  Applet  {  Button  buttonN,  buttonS,  buttonW,  buttonE,  buttonC;  

public  void  init()  {  setLayout(new  BorderLayout());  buttonN  =  new  Button(\"  reg;\");  buttonS  =  new  Button(\"火\");  buttonE  =  new  Button(\"木\");  buttonW  =  new  Button(\"金\");  buttonC  =  new  Button(\"土\");  add(\"North\",  buttonN);  add(\"South\",  buttonS);  add(\"East\",  buttonE);  add(\"West\",  buttonW);  add(\"Center\",  buttonC);  }  }  

6.1.1.3  网  格  布  局

网  格  布  局  把  面  板  分  成  一  个  个  的  网  格,  你  可  以  给  出  网  格  的  行  数  和  列  数。  下  面  是  一  个  网  格  布  局  的  例  子:  

import  java.awt.*;  import  java.applet.Applet;  

public  class  buttonGrid  extends  Applet  {  Button  button1,  button2,  button3,  button4,  button5,  button6,  button7,  button8;  

public  void  init()  {  setLayout(new  GridLayout(4,2));  button1  =  new  Button(\"乾\");  button2  =  new  Button(\"坤\");  button3  =  new  Button(\"艮\");  

button4  =  new  Button(\"震\");  button5  =  new  Button(\"坎\");  button6  =  new  Button(\"离\");  button7  =  new  Button(\"巽\");  button8  =  new  Button(\"兑\");  

add(button1);  add(button2);  add(button3);  add(button4);  add(button5);  add(button6);  add(button7);  add(button8);  }  }  

6.2  按  钮  

6.2.1  按  钮  事  件

用  户  点  一  下  按  钮,  就  会  有  一  个  按  钮  事  件  发  生。  你  可  以  通  过  覆  盖  一  个applet的action成  员  函  数  来  捕  捉  按  钮  事  件。  public  boolean  action  (Event  e,  Object  o)  {  if  (e.target  instanceof  Button)  {  system.out.println  ((string)  o);  }  else  {  System.out.println  (\"Non-button  event\");  }  return  true;  }  

6.2.2  按  钮  类  型  

Java提copy;  了  标  准  的  按  压  式  按  钮,  同  时  也  提copy;  了  选  择  式  按  钮  和  标  记  式  按  钮。  

6.2.2.1  选  择  式  按  钮  

选  择  式  按  钮  提copy;  了  从  几  个  选  项  中  选  一  个  选  项  的  功  能。  下  面  是  从  几  个  市  中  选  一  个  市  的  例  子,  市  名  放  在  选  择  式  按  钮  中:  

CityChooser  =  new  Choice();  

CityChooser.addItem(\"北copy;\");  CityChooser.addItem(\"上海\");  

CityChooser.addItem(\"天  津\");  

add(CityChooser);  

6.2.2.2  标  记  式  按  钮

标  记  式  按  钮  的  状  态  作  为  标  记  框  事  件  的  对  象  参  数  返  回。  下  面  是  一  个  标  记  式  按  钮  的  例  子:  

Checkbox  fillStyleButton;  fillStyleButton  =  new  Checkbox(\"Solid\");  

public  boolean  action(Event  e,  Object  arg)  {  if  (e.target  instanceof  

Checkbox)  {  System.out.println(\"Checkbox:  \"  +  arg);  }  return  true;  }  

6.2.2.3  按  键  式  按  钮

按  键  式  按  钮  是  一  组  按  钮,  用  户  可  以  选  中  其  中  一  个,  同  时  这  一  组  中  的  其  他  按  钮  将  被  关  闭。  下  面  是  一  个  按  键  式  按  钮  的  例  子:  public  class  CheckBox  extends  Applet  {  CheckboxGroup  cbg;  public  void  init()  {  cbg  =  new  CheckboxGroup();  add  (new  Checkbox(\"one  \",  cbg,  true));  add  (new  Checkbox(\"two  \",  cbg,false));  add  (new  Checkbox(\"three\",  cbg,  false));  }  }  

6.2.3  自  包  含  按  钮  

Java语  言  的  面  向  对  象  特  性  使  我  们  能  够  创  建  完  全  自  包  含  的  按  钮。  在  自  包  含  按  钮  里,  你  可  以  在copy;  展  按  钮  类  里  建  立  事  件  控  制  函  数。  下  面  是  一  个  自  包  含  按  钮  的  例  子:  

import  java.awt.*;  import  java.applet.Applet;  

class  okButton  extends  Button  {  

public  okButton()  {  setLabel(\"Ok\");  }  

public  boolean  action(Event  e,  Object  arg)  

{  System.out.println(\"OKButton\");  return  true;  }  }  

public  class  buttontest  extends  Applet  {  okButton  myOkButton;  

public  void  init()  {  myOkButton  =  new  okButton();  add(myOkButton);  }  }  

6.3  标copy;  

标copy;  是  一  种  放  到  面  板  上  的  静  止  的  正  文。  下  面  是  一  个  标copy;  的  例  子:  import  java.awt.*;  import  java.applet.Applet;  public  class  label  extends  Applet  {  public  void  init()  {  setLayout(new  FlowLayout(FlowLayout.CENTER,  10,  10));  Label  label1  =  new  Label(\"你  好!\");  Label  label2  =  new  Label(\"另  一  个  标copy;\");  add(label1);  add(label2);  }  }  

6.4  列  表  框  

列  表  框  使  用  户  易  于  操  作  大  量  的  选  项。  创  建  列  表  框  的  方  法  和Choice  button有copy;  相  似。  列  表  框  的  所  有  条  目  都  是  可  见  的,  如  果  选  项  很  多,  超  出  了  列  表  框  可  见  区  的  范  围,  则  列  表  框  的  旁  边  将  会  有  一  个  滚  动  条。  首  先,  创  建  列  表  框:  List  l  =  new  List(4,  false);  这  个  成  员  函  数  创  建  了  一  个  显  示4行  的  列  表  框。  第  二  个  参  数\"false\"表  示  这  个  列  表  框  是  单  选  的,  如  果  是\"true  \",  则  表  示  是  多  选  的。  下  面  增  加  列  表  框  的  选  项:  l.addItem(\"北copy;  大  学\");  l.addItem(\"清  华  大  学\");  l.addItem(\"吉林  大  学\");  l.addItem(\"复copy;  大  学\");  l.addItem(\"南  开  大  学\");  l.addItem(\"天  津  大  学\");  l.addItem(\"南copy;  大  学\");  add(l);  

6.4.1  在  列  表  框  中  进  行  选  择  

可  以  用  成  员  函  数getSelectedItem()或getSelectedItems()来  接  收  在  列  表  框  中  被  选  的  选  项。  在  单  选  列  表  框  里,\"  双  击\"  一  个  选  项  就  可  以  触  发  一  个  可  被action()成  员  函  数  捕  捉  到  的  事  件。  public  boolean  action(Event  e,  Object  arg)  {  .  .  .  if  (e.target  instanceof  List)  {  System.out.println(\"List  entry:\"  +  arg);  }  .  .  .  }  

6.4.2  多  选  列  表  框

对  于  多  选  列  表  框,  要  使  你  的  选  择  产  生  作  用,  需  要  使  用  其  他  的  外  部  事  件。  例  如,  你  可  以  使  用  按  钮  事  件:  public  boolean  action(Event  e,  Object  arg)  {  .  .  .  if  (e.target  instanceof  Button)  {  .  .  .  if  (\"Ok\".equals(arg))  {  string[]  selected  ;  selected  =  l.getSelectedItems(  );  for  (int  I  =  0;  I<  selected.length;  I++)  {System.out.println(selected[i]);  }  }  }  }  

6.5  文  本  域  

文  本  域  一  般  用  来  让  用  户  输  入  象  姓  名、  信  用  卡  号  这  样  的  信  息,  它  是  一  个  能  够  接  收  用  户  的  键  盘  输  入  的  小  块  区  域。  

6.5.1  创  建  文  本  域  

在  创  建  文  本  域  时,  有  四  种  类  型copy;  你  选  择:  空  的、  空  的  并  且  具  有  指  定  长  度、  带  有  初  始  文  本  内  容  的  和  带  有  初  始  文  本  内  容  并  具  有  指  定  长  度  的。  下  面  是  生  成  这  四  种  文  本  域  的  代  码:  TextField  tf1,  tf2,  tf3,  tf4;  //  空  的  文  本  域  tf1  =  new  TextField()  ;  //  长  度  为20的  空  的  文  本  域  tf2  =  new  TextField(20)  ;  //  带  有  初  始  文  本  内  容  的  文  本  域  tf3  

=  new  TextField(\"你  好\")  ;  //  带  有  初  始  文  本  内  容  并  具  有  指  定  长  度  的  文  本  域  tf4  =  new  TextField(\"你  好\",  30)  ;  add(tf1)  ;  add(tf2)  ;  add(tf3)  ;  add(tf4)  ;  

6.5.2  文  本  域  事  件  

当  用  户  在  文  本  域  里  敲\"  回  车\"  键  时,  就  产  生  了  一  个  文  本  域  事  件。  象  其  他  事  件  一  样,  你  可  以  以  在  成  员  函  数action()中  捕  捉  到  这  个  事  件。  

public  boolean  action(Event  e,  Object  arg)  {  .  .  .  if  (e.target  instanceof  TextField)  {  System.out.println(\"TextField:  \"+arg);  }  .  .  .  }  

6.6  文  本  区  

文  本  区  可  以  显  示  大  段  的  文  本。  

6.6.1  创  建  文  本  区

与  文  本  域  类  似,  创  建  文  本  区  时  也  有  四  种  类  型copy;  选  择,  但  如  果  指  定  文  本  区  的  大  小,  必  须  同  时  指  定  行  数  和  列  数。  TextArea  ta1,  ta2;  //  一  个  空  的  文  本  区  ta1  =  new  TextArea();  //  一  个  带  有  初  始  内  容、  大  小  为5  x  40  的  文  本  区  ta2  =  new  TextArea(\"你  好!\",  5,  40);  

可  以  用  成  员  函  数setEditable()来  决  定  用  户  是  否  可  对  文  本  区  的  内  容  进  行  编  辑。  //  使  文  本  区  为  只  读  的  ta2.setEditable(false)  

6.6.2  接  收  文  本  区  的  内  容

可  以  用  成  员  函  数getText()来  获  得  文  本  区  的  当  前  内  容。  例  如:  System.out.println(ta1.getText());  文  本  区  本  身  不  产  生  自  己  的  事  件。  但  你  可  以  用  外  部  事  件  来  接  收  文  本  区  的  内  容:  public  boolean  action(Event  e,  Object  o)  {  if  (e.target  instanceof  Button)  {  if  (\"send\".equals(o))  {  String  textToSend  =  ta1.getText  ();  

System.out.println(\"sending:  \"  +  textTosend);  

mySendFunction(textToSend);  }  }  else  {  .  .  .  }  }  

6.7  画  板

画  板  能  够  捕  捉  到copy;  露  事  件、  鼠  标  事  件  和  其  他  类  似  的  事  件。  基  本  的  画  板  类  不  处  理  这copy;  事  件,  但  你  可  以copy;  展  它  来  创  建  有  你  所  需  功  能  的  画  板  类。  

6.7.1  创  建  画  板  

import  java.awt.*;  import  java.applet.Applet;  

public  class  superGUI  extends  Applet  {  .  .  .  myCanvas  doodle;  .  .  .  public  

void  init()  {  .  .  .  //  建  立  我  们  的  画  板  doodle  =  new  myCanvas();  

doodle.reshape(0,  0,  100,  100);  leftPanel.add(\"Center\",doodle);  .  .  .  }  }  

class  myCanvas  extends  Canvas  {  public  void  paint(Graphics  g)  

{  g.drawRect(0,  0,  99,  99);  g.drawString(\"Canvas\",  15,  40);  }  }  

6.7.2  画  板  事  件  

你  可  以  覆  盖  一  般  的  事  件  处  理  成  员  函  数。  下  面  是  一  个  包  含  了mouseDown事  件  处  理  的  例  子:  import  java.awt.*;  import  java.applet.Applet;  

public  class  canvas  extends  Applet  {  

Button  b1;  

public  void  init()  {  //  Set  our  layout  as  a  Border  style  setLayout(new  

BorderLayout(15,  15));  b1  =  new  Button(\"Test\");  myCanvas  c1  =  new  

myCanvas(100,  100);  //  add  the  canvas  and  the  button  to  the  applet  

add(\"Center\",  c1);  add(\"South\",  b1);  }  

public  boolean  action(Event  e,  Object  arg)  {  System.out.println(\"Event:  

\"  +  arg);  return  true;  }  

public  boolean  mouseDown(Event  e,  int  x,  int  y)  

{  System.out.println(\"Mouse  works:  (\"  +  x  +  \",\"  +  y  +  \")\");  return  true;  }  }  

class  myCanvas  extends  Canvas  {  private  int  width;  private  int  height;  

public  myCanvas(int  w,  int  h)  {  width  =  w;  height  =  h;  reshape(0,  0,  w,  

h);  }  

public  void  paint(Graphics  g)  {  g.setColor(Color.blue);  g.fillRect(0,  0,  

width,  height);  }  

public  boolean  mouseDown(Event  e,  int  x,  int  y)  {  if  ((  x  <  width)  &&  (y  

第  七  章  多  线  程

7.1  多  线  程  的  概  念  

多  线  程  编  程  的  含  义  是  你  可  将  程  序  任  务  分  成  几  个  并  行  的  子  任  务。  特  别  是  在  网  络  编  程  中,  你  会  发  现  很  多  功  能  是  可  以  并  发  执  行  的。  比  如  网  络  传  输  速  度  较  慢,  用  户  输  入  速  度  较  慢,  你  可  以  用  两  个  独  立  的  线  程  去  完  成  这  ?copy;  功  能,  而  不  影  响  正  常  的  显  示  或  其  他  功  能。  多  线  程  是  与  单  线  程  比  较  而  言  的,  普  通  的WINDOWS采  用  单  线  程  程  序  结  构,  其  工  作  原  理  是:  主  程  序  有  一  个  消  息  循  环,  不  断  从  消  息  队  列  中  读  入  消  息  来  决  定  下  一  步  所  要  干  的  事  情,  一  般  是  一  个  子  函  数,  只  有  等  这  个  子  函  数  执  行  完  返  回  后,  主  程  序  才  能  接  收  另  外  的  消  息  来  执  行。  比  如  子  函  数  功  能  是  在  读  一  个  网  络  数  据,  或  读  一  个  文  件,  只  有  等  读  完  这  ?copy;  数  据  或  文  件  才  能  接  收  下  一  个  消  息。  在  执  行  这  个  子  函  数  过  程  中  你  什  么  也  不  能  干。  但  往  往  读  网  络  数  据  和  等  待  用  户  输  入  有  很  多  时  间  处  于  等  待  状  态,  多  线  程  利  用  这  个  特  点  将  任  务  分  成  多  个  并  发  任  务  后,  就  可  以  解  决  这  个  问  题。  

7.1.1  Java线  程  的  模  型  

Java的  设  计  思  想  是  建  立  在  当  前  大  多  数  操  作  系  统  都  实  现  了  线  程  调  度。Java虚  拟  机  的  很  多  任  务  都  依  赖  线  程  调  度,  而  且  所  有  的  类  库  都  是  为  多  线  程  设  计  的。  实  时  上,Java支  持Macintosh和Ms-dos  的  平  台  ?reg;  所  以  迟  迟  未  出  来  就  是  因  为  这  两  个  平  台  都  不  支  持  多  线  程。Java利  用  多  线  程  实  现  了  整  个  执  行  环  境  是  异  步  的。  在Java程  序  里  没  有  主  消  息  循  环。  如  果  一  个  线  程  等  待  读  取  网  络  数  据,  它  可  以  运  行  但  不  停  止  系  统  的  其  他  线  程  执  行。  用  于  处  理  用  户  输  入  的  线  程  大  多  时  间  是  等  待  用  户  敲  键  盘  或  击  鼠  标。  你  还  可  以  使  动  画  的  每  一  帧  ?reg;  间  停  顿  一  秒  而  并  不  使  系  统  暂  停。  一  ?copy;  线  程  启  动  后,  它  可  以  被  挂  起,  暂  时  不  让  它  执  行。  挂  起  的  线  程  可  以  重  新  恢  复  执  行。  任  何  时  间  线  程  都  可  以  被  停  止,  被  停  止  的  线  程  就  不  能  再  重  新  启  动。  Java语  言  里,  线  程  表  现  为  线  程  类,  线  程  类  封  装  了  所  有  需  要  的  线  程  操  作  控  制。  在  你  心  里,  必  须  很  清  晰  地  区  分  开  线  程  对  象  和  运  行  线  程,  你  可  以  将  线  程  对  象  看  作  是  运  行  线  程  的  控  制  面  板。  在  线  程  对  象  里  有  很  多  函  数  来  控  制  一  个  线  程  是  否  运  行,  睡  眠,  挂  起  或  停  止。  线  程  类  是  控  制  线  程  行  为  的  唯  一  的  手  段。  一  ?copy;  一  个Java程  序  启  动  后,  就  已  经  有  一  个  线  程  在  运  行。  你  可  通  过  调  用Thread.currentThread  函  数  来  查  看  当  前  运  行  的  是  哪  一  个  线  程。  

你  得  到  一  个  线  程  的  控  制  柄,  你  就  可  以  作  很  有  趣  的  事  情,  即  使  单  线  程  也  一  样。  下  面  这  个  例  子  让  你  知  道  怎  样  操  纵  当  前  线  程。  Filename:testthread  

class  testthread  {  public  static  void  main(String  args[])  {  Thread  t  

=Thread.currentThread();  t.setName(\"This  Thread  is  running\");  

System.out.println(\"The  running  thread:\"  +  t);  try  {  for  (int  i=0;i<5;i++)  

{  System.out.println(\"Sleep  time  \"+i);  Thread.sleep(1000);  }  

}  catch  (InterruptedException  e)  {System.out.println(\"thread  has  wrong\");  }  

}  }  

执  行  结  果:java  testthread  The  running  thread:Thread[This  Thread  is  running,5,main]  Sleep  time  0  Sleep  time  1  Sleep  time  2  Sleep  time  3  Sleep  time  4  

7.1.2  启  动  接  口

一  个  线  程  并  不  激  动  人  心,  多  个  线  程  才  有  实  际  意  义。  我  们  怎  样  创  建  更  多  的  线  程  呢?  我  们  需  要  创  建  线  程  类  的  另  一  个  实  例。  当  我  们  构  造  了  线  程  类  的  一  个  新  的  实  例,  我  们  必  须  告  诉  它  在  新  的  线  程  里  应  执  行  哪  一  段  程  序。  你  可  以  在  任  意  实  现  了  启动  接  口  的  对  象  上  启  动  一  个  线  程。  启  动  接  口  是  一  个  抽  象  接  口,  来  表  示  本  对  象  有  一  ?copy;  函  数  想  异  步  执  行。  要  实  现  启  动  接  口,  一  个  类  只  需  要  有  一  个  叫run的  函  数。  下  面  是  创  建  一  个  新  线  程  的  例  子:  

Filename:twothread.java  

class  twothread  implements  Runnable  {  twothread()  {  Thread  t1  

=Thread.currentThread();  t1.setName(\"The  first  main  thread\");  

System.out.println(\"The  running  thread:\"  +  t1);  Thread  t2  =  new  

Thread(this,\"the  second  thread\");  System.out.println(\"creat  another  

thread\");  t2.start();  try  {  System.out.println(\"first  thread  will  

sleep\");  Thread.sleep(3000);  }catch  (InterruptedException  e)  

{System.out.println(\"first  thread  has  wrong\");  }  

System.out.println(\"first  thread  exit\");  }  public  void  run()  {  try  {  for  

(int  i=0;i<5;i++)  {  System.out.println(\"Sleep  time  for  thread  2:\"+i);  

Thread.sleep(1000);  }  

}  catch  (InterruptedException  e)  {System.out.println(\"thread  has  

wrong\");  }  

System.out.println(\"second  thread  exit\");  }  public  static  void  

main(String  args[])  {  new  twothread();  }  }  

执  行  结  果:java  twothread  

The  running  thread:Thread[The  first  main  thread,5,main]  creat  another  

thread  first  thread  will  sleep  Sleep  time  for  thread  2:0  Sleep  time  for  

thread  2:1  Sleep  time  for  thread  2:2  first  thread  exit  Sleep  time  for  

thread  2:3  Sleep  time  for  thread  2:4  second  thread  exit  

main线  程  用new  Thread(this,  \"the  second  thread\")创  建  了  一  个Thread对  象,  通  过  传  递  第  一  个  参  数  来  标  明  新  线  程  来  调  用this对  象  的run函  数。  然  后  我  们  调  用start函  数,  它  将  使  线  程  从run函  数  开  始  执  行。  

7.1.3  同  步  

因  为  多  线  程  给  你  提  ?copy;  了  程  序  的  异  步  执  行  的  功  能,  所  以  在  必  要  时  必  须  还  提  ?copy;  一  种  同  步  机  制。  例  如,  你  想  两  个  线  程  通  讯  并  共  享  一  个  复  杂  的  数  据  结  构,  你  需  要  一  种  机  制  让  他  们  相  互  牵  制  并  正  确  执  行。  为  这  个  目  的,Java用  一  种  叫  监  视  器(monitor)的  机  制  实  现  了  进  程  间  的  异  步  执  行。  可  以  将  监  视  器  看  作  是  一  个  很  小  的  盒  子,  它  只  能  容  纳  一  个  线  程。  一  ?copy;  一  个  线  程  进  入  一  个  监  视  器,  所  有  其  他  线  程  必  须  等  到  第  一  个  线  程  退  出  监  视  器  后  才  能  进  入。  这  ?copy;  监  视  器  可  以  设  计  成  保  护  共  享  的  数  据  不  被  多  个  线  程  同  时  操  作。  大  多  数  多  线  程  系  统  将  这  ?copy;  监  视  器  设  计  成  对  象,Java提  ?copy;  了  一  种  更  清  晰  的  解  决  方  案。  没  有Monitor类;  每  个  对  象  通  过  将  他  们  的  成  员  函  数  定  义  成synchronized来  定  义  自  己  的  显  式  监  视  器,  一  ?copy;  一  个  线  程  执  行  在  一  个synchronized函  数  里,  其  他  任  何  线  程  都  不  能  调  用  同  一  个  对  象  的  

synchronized函  数。  

7.1.4  消  息  

你  的  程  序  被  分  成  几  个  逻  辑  线  程,  你  必  须  清  晰  的  知  道  这  ?copy;  线  程  ?reg;  间  应  怎  样  相  互  通  讯。Java  提  了wait和notify等  功  能  来  使  线  程  ?reg;  间  相  互  交  谈。  一  个  线  程  可  以  进  入  某  一  个  对  象  的synchronized  函  数  进  入  等  待  状  态,  直  到  其  他  线  程  显  式  地  将  它  唤  醒。  可  以  有  多  个  线  程  进  入  同  一  个  函  数  并  等  待  同  一  个  唤  醒  消  息。  

7.2  Java线  程  例  子  

7.2.1  显  式  定  义  线  程  

在  我  们  的  单  线  程  应  用  程  序  里,  我  们  并  没  有  看  见  线  程,  因  为Java能  自  动  创  建  和  控  制  你  的  线  程。  如  果  你  使  用  了  理  解Java语  言  的  浏  览  器,  你  就  已  经  看  到  使  用  多  线  程  的Java程  序  了。  你  也  许  注  意  到  两  个  小  程  序  可  以  同  时  运  行,  或  在  你  移  动  滚  动  条  时  小  程  序  继  续  执  行。  这  并  不  是  表  明  小  程  序  是  多  线  程  的,  但  说  明  这  个  浏  览  器  是  多  线  程  的。  多  线  程  应  用  程  序(或applet)可  以  使  用  好  几  个  执  行  上  下  文  来  完  成  它  们  的  工  

作。  多  线  程  利  用  了  很  多  任  务  包  含  单  独  的  可  分  离  的  子  任  务  的  特  点。  每  一  个  线  程  完  成  一  个  子  任  务。  但  是,  每  一  个  线  程  完  成  子  任  务  时  还  是  顺  序  执  行  的。  一  个  多  线  程  程  序  允  许  各  个  线  程尽快  执  行  完  它  们。  这  种  特  点  会  有  更  好  的  实  时  输  入  反  应。  

7.2.2  多  线  程  例  子

下  面  这  个  例  子  创  建  了  三  个  单  独  的  线  程,  它  们  分  别  打  印  自  己  的\"Hello  World\":  

//Define  our  simple  threads.They  will  pause  for  a  short  time  //and  then  

print  out  their  names  and  delay  times  class  TestThread  extends  Thread  

{  private  String  whoami;  private  int  delay;  

//Our  constructor  to  store  the  name  (whoami)  //and  time  to  sleep  (delay)  

public  TestThread(String  s,  int  d)  {  whoami  =  s;  delay  =  d;  }  

//Run  -  the  thread  method  similar  to  main()  //When  run  is  finished,  the  

thread  dies.  //Run  is  called  from  the  start()  method  of  Thread  public  void  

run()  {  //Try  to  sleep  for  the  specified  time  try  {  sleep(delay);  }  

catch(InterruptedException  e)  {}  //Now  print  out  our  name  

System.out.println(\"Hello  World!\"+whoami+\"\"+delay);  }  }  /**  *  Multimtest.  

A  simple  multithread  thest  program  */  public  class  multitest  {  public  

static  void  main(String  args[])  {  TestThread  t1,t2,t3;  //Create  our  test  

threads  t1  =  new  TestThread(\"Thread1\",(int)(Math.readom()*2000));  t2  =  

new  TestThread(\"Thread2\",(int)(Math.readom()*2000));  t3  =  new  

TestThread(\"Thread3\",(int)(Math.readom()*2000));  

//Start  each  of  the  threads  t1.start();  t2.start();  t3.start();  }  }  

7.2.3  启  动  一  个  线  程  

程  序  启  动  时  总  是  调  用main()函  数,  因  此main()是  我  们  创  建  和  启  动  线  程  的  地  方:  

t1  =  new  TestThread(\"Thread1\",(int)(Math.readom()*2000));  

这  一  行  创  建  了  一  个  新  的  线  程。  后  面  的  两  个  参  数  传  递  了  线  程  的  名  称  和  线  程  在  打  印  信  息  ?reg;  前  的  延  时  时  间。  因  为  我  们  直  接  控  制  线  程,  我  们  必  须  直  接  启  动  它:  t1.start();  

7.2.4  操  作  线  程  

如  果  创  建  线  程  正  常,t1应  包  含  一  个  有  效  的  执  行  线  程。  我  们  在  线  程  的run()函  数  里  控  制  线  程。  一  ?copy;  我  们  进  入run()函  数,  我  们  便  可  执  行  里  面  的  任  何  程  序。run()好  象main()一  样。  

run()  执  行  完,  这  个  线  程  也  就  结  束  了。  在  这  个  例  子  里,  我  们  试  着  延  迟  一  个  随  机  的  时  间(通  过  参  数  传  递?)  sleep(delay);  

sleep()函  数  只  是  简  单  地  告  诉  线  程  休  息  多  少  个  毫  秒  时  间。  

如  果  你  想  推  迟  一  个  线  程  的  执  行,  你  应  使  用sleep()函  数。  当  线  程  睡  眠  是sleep()并  不  占  用  系  统  资  源。  其  它  线  程  可  继  续  工  作。  一  ?copy;  延  迟  时  间  完  毕,  它  将  打  印\"Hello  World\"和  线  程  名  称  及  延  迟  时  间。  

7.2.5  暂  停  一  个  线  程

我  们  经  常  需  要  挂  起  一  个  线  程  而  不  指  定  多  少  时  间。  例  如,  如  果  你  创  建  了  一  个  含  有  动  画  线  程  的  小  程  序。  也  许  你  让  用  户  暂  停  动  画  至  到  他  们  想  恢  复  为  止。  你  并  不  想  将  动  画  线  程  仍  调,  但  想  让  它  停  止。  象  这  种  类  似  的  线  程  你  可  用suspend()函  数  来  控  制:  t1.suspend();  这  个  函  数  并  不  永  久  地  停  止  了  线  程,  你  还  可  用resume()函  数  重  新  激  活  线  程:  t1.resume();  

7.2.6  停  止  一  个  线  程  

线  程  的  最  后  一  个  控  制  是  停  止  函  数stop()。  我  们  用  它  来  停  止  线  程  的  执  行:  t1.stop();  

注  意:  这  并  没  有  消  灭  这  个  线  程,  但  它  停  止  了  线  程  的  执  行。  并  且  这  个  线  程  不  能  用t1.start()重  新  启  动。  在  我  们  的  例  子  里,  我  们  从  来  不  用  显  式  地  停  止  一  个  线  程。  我  们  只  简  单  地  让  它  执  行  完  而  已。  很  多  复  杂  的  线  程  例  子  将  需  要  我  们  控  制  每  一  个  线  程。  在  这  种  情  况  下  会  使  用  到stop()函  数。  如  果  需  要,  你  可  以  测  试  你  的  线  程  是  否  被  激  活。  一  个  线  程  已  经  启  动  而  且  没  有  停  止  被  认  为  是  激  活  的。  t1.isAlive()  如  果t1是  激  活  的,  这  个  函  数  将  返  回true.  

7.2.7  动  画  例  子  

下  面  是  一  个  包  含  动  画  线  程  的applet例  子:  

import  java.awt.*;  import  java.awt.image.ImageProducer;  import  

java.applet.Applet;  

public  class  atest3  extends  Applet  implements  Runnable  {  Image  images[];  

MediaTracker  tracker;  int  index  =  0;  Thread  animator;  

int  maxWidth,maxHeight;  //Our  off-screen  components  for  double  buffering.  

Image  offScrImage;  Graphics  offScrGC;  

//Can  we  paint  yes?  boolean  loaded  =  false;  

//Initialize  the  applet.  Set  our  size  and  load  the  images  public  void  init()  

[  //Set  up  our  image  monitor  tracker  =  new  MediaTracker(this);  

//Set  the  size  and  width  of  our  applet  maxWidth  =  100;  maxHeight  =100;  

images  =  new  Image[10];  //Set  up  the  double-buffer  and  resize  our  applet  

try  {  offScrImage  =  createImage(maxWidth,maxHeight);  offScrGC  =  

offScrImage.getGraphics();  offScrGC.setColor(Color.lightGray);  

offScrGC.fillRect(0,0,maxWidth,maxHeight);  

resize(maxWidth,maxHeight);  }catch  (Exception  e)  

{  e.printStackTrace();  }  

//load  the  animation  images  into  an  array  for  (int  i=0;i<10;i++)  {  String  

imageFile  =  new  String  (\"images/Duke/T\"  +String.valueOf(i+1)  +\".gif\");  

images[i]  =  getImage(getDocumentBase(),imageFile):  //Register  this  

image  with  the  tracker  tracker.addImage(images[i],i);  }  try  {  //Use  

tracker  to  make  sure  all  the  images  are  loaded  tracker.waitForAll();  }  

catch  (InterruptedException  e)  {}  loaded  =  true;  }  

//Paint  the  current  frame.  public  void  paint  (Graphics  g)  {  if  (loaded)  

{  g.drawImage(offScrImage,0,0,this);  }  }  

//Start  ,setup  our  first  image  public  void  start()  {  if  (tracker.checkID  

(index))  {  offScrGC.drawImage  (images[index],0,0,this);  }  animator  =  new  

Thread(this);  animator.start();  }  

//Run,do  the  animation  work  here.  //Grab  an  image,  pause  ,grab  the  next...  

public  void  run()  {  //Get  the  id  of  the  current  thread  Thread  me  =  

Thread.currentThread();  

//If  our  animator  thread  exist,and  is  the  current  thread...  while  

((animatr!=  null)  &&  (animator==me))  {  if  (  tracker.checkID  (index))  

{  //Clear  the  background  and  get  the  next  image  

offScrGC.fillRect(0,0,100,100);  

offScrGCdrawImage(images[index],0,0,this);  index++;  //Loop  back  to  the  

beginning  and  keep  going  if  (index>=  images.length)  {  index  =  0;  }  }  

//Delay  here  so  animation  looks  normal  try  {  animator.sleep(200);  }catch  

(InterruptedException  e)  {}  //Draw  the  next  frame  repaint();  }  }  }  

7.3  多  线  程  间  的  通  讯

7.3.1  生  产  者  和  消  费  者  

多  线  程  的  一  个  重  要  特  点  是  它  们  ?reg;  间  可  以  互  相  通  讯。  你  可  以  设  计  线  程  使  用  公  用  对  象,  每  个  线  程  都  可  以  独  立  操  作  公  用  对  象。  典  型  的  线  程  间  通  讯  建  立  在  生  产  者  和  消  费  者  模  型  上:  一  个  线  程  产  生  输  出;  另  一  个  线  程  使  用  输  入buffer  

让  我  们  创  建  一  个  简  单  的\"Alphabet  Soup\"生  产  者  和  相  应  的  消  费  者.  

7.3.2  生  产  者  

生  产  者  将  从thread类  里  派  生:  class  Producer  extends  Thread  

{  private  Soup  soup;  private  String  alphabet  =  \"  

ABCDEFGHIJKLMNOPQRSTUVWXYZ\";  

public  Producer(Soup  s)  {  //Keep  our  own  copy  of  the  shared  object  soup  

=  s;  }  

public  void  run()  {  char  c;  //Throw  10  letters  into  the  soup  for  (int  

i=0;i<10;i++)  {  c  =  alphabet.charAt((int)(Math.random()  *26));  

soup.add(c);  //print  a  record  of  osr  addition  

System.out.println(\"Added\"+c  +  \"to  the  soup.\");  //wait  a  bit  before  we  

add  the  next  letter  try  {  sleep((int)(Math.random()  *1000));  }  catch  

(InterruptedException  e)  {}  }  }  }  

注  意  我  们  创  建  了Soup类  的  一  个  实  例。  生  产  者  用soup.add()函  数  来  建  立  字  符  池。  

7.3.3  消  费  者

让  我  们  看  看  消  费  者  的  程  序:  class  Consumer  extends  Thread  {  private  Soup  soup;  

public  Consumer  (Soup  s)  {  //keep  our  own  copy  of  the  shared  object  soup  

=  s;  }  

public  void  run()  {  char  c;  //Eat  10  letters  from  the  alphabet  soup  for  

(int  I=0  ;i<10;i++)  {  //grab  one  letter  c  =  soup.eat();  //Print  out  the  

letter  that  we  retrieved  System.out.println(\"Ate  a  letter:  \"  +c);  //try  

{  sleep((int)(Math.raddom()*2000));  }  catch  (InterruptedException  e)  {}  }  }  }  

同  理,  象  生  产  者  一  样,  我  们  用soup.eat()来  处  理  信  息。  那  么,Soup类  到  底  干  什  么  呢?  

7.3.4  监  视  

Soup类  执  行  监  视  两  个  线  程  ?reg;  间  传  输  信  息  的  功  能。  监  视  是  多  线  程  中  不  可  缺  少  的  一  部  分,  因  为  它  保  持  了  通  讯  的  流  ?copy;。  让  我  们  看  看Soup.java文  件:  class  Soup  {  private  char  buffer[]  =  new  char[6];  private  int  next  =  0;  //Flags  to  keep  track  of  

our  buffer  status  private  boolean  isFull  =  false;  private  boolean  isEmpty  

=  true;  public  syschronized  char  eat()  {  //We  can\'t  eat  if  there  isn\'t  anything  

in  the  buffer  while  (isEmpty  ==  true)  {  try  {  wait()  ;//we\'ll  exit  this  

when  isEmpty  turns  false  }catch  (InterruptedException  e)  {}  }  //decrement  

the  count,since  we\'re  going  to  eat  one  letter  next--;  //Did  we  eat  the  

last  letter?  if  (next==  0)  {  isEmpty  =  true;  }  //We  know  the  buffer  can\'t  

be  full,because  we  just  ate  isFull  =  false;  notify();  //return  the  letter  

to  the  thread  that  is  eating  return  (buffer[next]);  }  

//method  to  add  letters  to  the  buffer  public  synchronized  void  add(char  

c)  {  //Wait  around  until  there\'s  room  to  add  another  letter  while  (isFull  

==  true  )  {  try{  wait();//This  will  exit  when  isFull  turns  false  }catch  

(InterruptedException  e)  {}  }  //add  the  letter  to  the  next  available  spot  

buffer[next]=c;  //Change  the  next  available  spot  next++;  //Are  we  full;  

if  (next  ==6)  {  isFull  =true;  }  isEmpty  =false;  notify();  }  }  soup类  包  含  两  个  重  要  特  征:  数  据  成  员buffer[]是  私  有  的,  功  能  成  员add()和eat()是  公  有  的。  

数  据  私  有  避  免  了  生  产  者  和  消  费  者  直  接  获  得  数  据。  直  接  访  问  数  据  可  能  造  成  错  误。  例  如,  如  果  消  费  者  企  图  从  空  缓  冲  区  里  取  出  数  据,  你  将  得  到  不  必  要  的  异  常,  否  则,  你  只  能  锁  住  进  程。  同  步  访  问  方  法  避  免  了  破  坏  一  个  共  享  对  象。  当  生  产  者  向soup里  加  入  一  个  字  母  时,  消  费  者  不  能  吃  字  符,  诸  如  此  类。  这  种  同  步  是  维  持  共  享  对  象  完  整  性  的  重  要  方  面。notify()函  数  将  唤  醒  每  一  个  等  待  线  程。  等  待  线  程  将  继  续  它  的  访  问。  

7.3.5  联  系  起  来  

现  在  我  们  有  一  个  生  产  者,  一  个  消  费  者  和  一  个  共  享  对  象,  怎  样  实  现  它  们  的  交  互  呢?  我  们  只  需  要  一  个  简  单  的  控  制  程  序  来  启  动  所  有  的  线  程  并  确  信  每  一  个  线  程  都  是  访  问  的  同  一  个  共  享  对  象。  下  面  是  控  制  程  序  的  代  码,SoupTest.java:  

class  SoupTest  {  public  static  void  main(String  args[])  {  Soup  s  =  new  

Soup();  Producer  p1  =  new  Producer(s);  Consumer  c1  =  new  Consumer(s);  

p1.start();  c1.start();  }  }  

7.3.6  监  视  生  产  者  

生  产  者/消  费  者  模  型  程  序  经  常  用  来  实  现  远  程  监  视  功  能,  它  让  消  费  者  看  到  生  产  者  同  用  户  的  交  互  或  同  系  统  其  它  部  分  的  交  互。  例  如,  在  网  络  中,  一  组  生  产  者  线  程  可  以  在  很  多  工  作  站  上  运  行。  生  产  者  可  以  打  印  文  档,  文  档  打  印  后,  一  个  标  志  将  保  存  下  来。  一  个(或  多  个?copy;  消  费  者  将  保  存  标  志  并  在  晚  上  报  告  白  天  打  印  活  动  的  情  况。  另  外,  还  有  例  子  在  一  个  工  作  站  是  分  出  几  个  独  立  的  窗  口。  一  个  窗  口  用  作  用  户  输  入(生  产  者)  另  一  个  窗  口  作  出  对  输  入  的  反  应(消  费  者)。  

7.4  线  程API列  表  

下  面  是  一  个  常  用  的  线  程  类  的  方  法  函  数  列  表:  类  函  数:  以  下  是Thread的  静  态  函  数,  即  可  以  直  接  从Thread类  调  用。  

currentThread  返  回  正  在  运  行  的Thread对  象  yield  停  止  运  行  当  前  线  程,  让  系  统  运  行  下  一  个  线  程  sleep(int  n)  让  当  前  线  程  睡  眠n毫  秒  对  象  函  数:  以  下  函  数  必  须  用Thread的  实  例  对  象  来  调  用。  

start  start函  数  告  诉java运  行  系  统  为  本  线  程  建  立  一  个  执  行  环  境,  然  后  调  用  本  线  程  的run()函  数。  run  是  运  行  本  线  程  的  将  要  执  行  的  代  码,  也  是Runnable接  口  的  唯  一  函  数。  当  一  个  线  程  初  始  化  后,  由start函  数  来  调  用  它,  一  ?copy;run函  数  返  回,  本  线  程  也  就  终  止  了。  stop  让  某  线  程  马  上  终  止,  系  统  将  删  除  本  线  程  的  执  行  环  境  suspend  与stop函  数  不  同,suspend将  线  程  暂  停  执  行,  但  系  统  不  破  坏  线  程  的  执  行  环  境,  你  可  以  用resume来  恢  复  本  线  程  的  执  行  resume  恢  复  被  挂  起  的  线  程  进  入  运  行  状  态  setPriority(int  p)  给  线  程  设  置  优  先  级  getPriority  返  回  线  程  的  优  先  级  setName(String  name)  给  线  程  设  置  名  称  getName  取  线  程  的  名  称  

本  章  小  结:  

1.多  线  程  是java语  言  的  重  要  特  点,java语  言  用Thread类  封  装  了  线  程  的  所  有  操  作。  2.线  程  的  接  口  名  为Runnable  3.线  程  间  同  步  机  制  为synchronized关  键  词  4.线  程  间  通  讯  靠wait与notify消  息  

第  八  章  Java的\"  异  常\"

\"  异  常\"  指  的  是  程  序  运  行  时  出  现  的  非  正  常  情  况。  在  用  传  统  的  语  言  编  程  时,  程  序  员  只  能  通  过  函  数  的  返  回  值  来  发  出  错  误  信  息。  这  易  于  导  致  很  多  错  误,  因  为  在  很  多  情  况  下  需  要  知  道  错  误  产  生  的  内  部  细  节。  通  常,  用  全  局  变  量errno来  存  储\"  异  常\"  的  类  型。  这  容  易  导  致  误  用,  因  为  一  个errno的  值  有  可  能  在  被  处  理  ?reg;  前  被  另  外  的  错  误  覆  盖  掉。  即  使  最  优  美  的C语  言  程  序,  为  了  处  理\"  异  常\"  情  况,  也  常  求  助  于goto语  句。  Java对\"  异  常\"  的  处  理  是  面  向  对  象  的。  一  个Java的Exception是  一  个  描  述\"  异  常\"  情  况  的  对  象。  当  出  现\"  异  常\"  情  况  时,  一  个Exception对  象  就  产  生  了,  并  放  到  产  生  这  个\"  异  常\"  的  成  员  函  数  里。  

8.1  基础  

Java的\"  异  常\"  处  理