Java2实用教程(三)

时间:2008-06-29 12:33:22  类别:java教程  作者:william750214

第十九章 Java多线程机制

一、Java中的线程

1、线程的状态与生命周期

1)新建:当一个Thread类或其子类对象被声明并创建时、新生的线程对象处于新建状态。

2)就绪:处于新建状态的线程启动后。

3)运行:获得CPU资源。

4)中断:可以被人为的中断进入阻塞状态,只有当引起阻塞的原因消除时、线程才可以转入就绪状态,重新进到线程队列中排队。

5)死亡:完成全部工作或被提前强制地中止。

2、线程调度与优先级

Java中线程调度依据优先级基础上的“先到先服务”原则。

java.lang.Thread类中的方法:public void setPriority(int newPriority)设置线程优先级。newPriority的取值为以下的常量:

Thread.MIN_PRIORITYThread.MAX_PRIORITYThread.NORM_PRIORITY(默认级别)

二、Thread类与Runnable接口

1Thread

1)构造函数

public Thread (Runnable target):创建线程对象,target称为被创建线程的目标对象。创建目标对象target的类负责实现Runnable接口,给出该接口中public void run ( )方法的方法体。

2)其他主要方法

public void start ( ):线程调用该方法将启动线程,进入就绪状态,一旦获得CPU就开始自己的生命周期。一个线程对象只启动一次。

public void run ( ):用来定义线程对象被调度之后所执行的操作,都是系统自动调用而用户不得引用的方法。当然该方法执行完毕,线程就变成死亡状态。在线程没有结束run方法之前,不赞成让线程再调用start方法,否则将发生ILLegalThreadStateException异常。

public static void sleep int millsecond:线程的调度执行是按照其优先级的高低顺序执行的,当高级线程不完成,低级线程就没有机会获得CPU。为了让出CPU给低优先级的线程。可以在高优先级的线程的run方法中使用sleep方法休眠。

public boolean isAlive ( ):测试线程是否依然存活,杀死不存在的线程会出现异常,所以先测试一下。

public static void yield()Causes the currently executing thread object to temporarily pause and allow other threads to execute.

public static Thread currentThread ( ):判断当前正在占用CPU的线程

public String getName ( ):获取线程的名字

public void setName (String s):设置线程的内部名称

后台线程:

public void setDaemon (boolean):设置线程是否为后台,默认为前台,true为后台

注:当一个子线程A调用另外一个子线程B时,当A设为后台时,如主线程结束,则B也结束。

联合线程:

public void join ( )

public void join (long millis)

2Runnable接口:只有一个run()方法

三、如何在程序中实现多线程

1、用Thread类的子类创建线程

在子类中重写父类的run( )方法,该方法中包括了线程的操作。

注意:如果用Thread类的子类同时生产多个线程对象,它们不共享类中的成员。

2、用Thread类创建线程

public Thread (Runnalbe target):构造方法中的参数必须是称作线程的目标对象,创建目标对象的类必须要实现Runnable接口。

例:class Mywin extends Frame implements Runnable

{

public void run ( )

{

sleep (int a);

}

}

1)可以使用booleanflag来杀死线程(run()方法执行完毕返回)

2)可以使用一个实现Runnable接口中的run()方法来为多个线程服务,使用Thread类中的静态方法currentThread()来判断执行响应的程序段。共享那个实现Runnable接口的对象成员。

3Thread类中的静态方法sleep()

四、线程同步机制(牺牲程序性能为代价

1、在处理线程同步时,要做的第一件事就是要把修改数据的方法用关键字synchronized来修饰。一个方法使用synchronized修饰后,当一个线程A使用此方法时,其他线程想使用此方法时就必须等待,直到线程A使用完该方法。

2、原子代码块

synchronized (任意对象)

{

}

一般任意对象使用字符串String flag锁棋标

一定要注意不能把String flag的定义放到run方法中

或者使用synchronized方法,原理一样,效果一样

同时使用synchronized代码块和synchronized方法,使用this对象作为监视器

3、死锁

使用synchronized代码块和synchronized方法时相互嵌套导致互相等待,发生死锁。

五、在同步方法中使用wait()、notify()notifyAll()方法(属于Object类中的方法)(线程通信

当一个线程使用的同步方法中用到某个变量,而此变量又需要其他线程修改后才能符合本线程的需要,那么可以在同步方法中使用wait()方法。使用wait()方法可以中断线程的执行,使本线程处于等待状态,暂时让出CPU的使用权,并允许其他线程使用这个同步方法。其他线程如果在使用这个同步方法时不需要等待,那么它使用完这个同步方法的同时,应当用noticeAll()方法通知所有的由于使用这个同步方法而处于等待的线程结束等待。曾经中断的线程就会从刚才的中断处继续执行这个同步方法,并遵循“先中断先继续”的原则。如果只使用notify()方法,则只通知第一个处于等待的线程结束等待。

注:在synchronized代码块中必须使用flag.wait ( )flag.notify ( )(为this时可省略)

六、线程的interrupt()方法

一个线程在执行完run()方法后就自动的消灭了,如果想在run方法执行完之前就消灭该线程,可以让线程调用interrupt()方法,这时该线程就会捕获InterruptedExcepiton异常在处理该异常的语句里告诉线程结束run()方法的执行,如return语句或break语句等。在捕获sleep()方法的InterruptedException异常中加入就可以了。

注:(1)在开始某个线程之前必须使用isAlive()方法测试该线程是否是活的,捕获线程开始start( )方法的异常;

2)在分配一个线程实体之前必须使用isAlive()方法测试该线程是否是活的,否则将产生不能被垃圾回收机制回收的内存垃圾

第二十章 输入输出流

一、运行可执行文件

使用Runtime类(java.lang包中)

二、注:用文件长度控制读写结束。文件指针 <文件长度

三、对象流

ObjectInputStream类和ObjectOutputStream

这两个流允许程序读写对象

注:要保证对象是序列化的。实现Serializable接口(该接口中没有任何方法)则为序列化的对象。一个序列化类的子类创建的对象也是序列化的。

四、Process类中的流

使用Runtime类中的exec运行一个可执行文件,即启动一个进程,exec返回一个Process对象

getErrorStream ( ):获取该进程错误信息的输入流

getInputStream( ): 获取该进程的输入流

getOutputStream( ):获取该进程的输出流

以上三个方法返回InputStreamOutStream类的对象,该类对象的读写是字节方式

五、了解打印流(输出流):PrintStream:过滤各种数据格式(甚至为Object型)为字符串。

六、字节输入、输出流。流的源和目标除了可以是文件外,还可以是计算机的内存

ByteArrayInputStream ByteArrayOutputStream

第二十一章Java网络的基本知识

一、使用URL

Applet中的方法getAppletContext()

showDocument()实际完成另一个web页面的工作。程序只须提供URL

例:getAppletContext().showDocument(url)

二、套接字(Socket

1、客户建立连接到服务器

例子:

sc = new Socket ("localhost", 2000);

in = new DataInputStream (sc.getInputStream ( ));

out = new DataOutputStream (sc.getOutputStream ( ));

2ServerSocket

服务器必须建立一个等待接收客户的套接字的ServerSocket对象。建立后就可以用accept()方法接收客户的套接字连接呼叫。所谓的“接收”客户的套接字就是accept()方法返回一个和客户端Socket对象相连接的Socket对象。

3、注意与从文件中读写数据的区别。如果没有数据就读,就会堵塞本线程,直到读取方法成功读取到信息,本线程才继续执行后续的操作。另外、accept()方法也会堵塞线程的继续执行,直到收到客户的呼叫。一般把数据的输入输出放入单独的线程中去执行。

4、连接建立后服务器端的套接字对象调用getInetAddress()方法就可以获取一个InetAddress对象。同样,客户端也是。

5Applet类中的getCodeBase()方法返回URL,然后使用URL中的getHost()方法返回字符串。

getCodeBase().getHost()

三、把套接字连接放在一个线程中

四、InetAddress


特别推荐

广而告之