Java面向对象程序设计教程(第二版)线程、输入﹨输出ppt.ppt_第1页
Java面向对象程序设计教程(第二版)线程、输入﹨输出ppt.ppt_第2页
Java面向对象程序设计教程(第二版)线程、输入﹨输出ppt.ppt_第3页
Java面向对象程序设计教程(第二版)线程、输入﹨输出ppt.ppt_第4页
Java面向对象程序设计教程(第二版)线程、输入﹨输出ppt.ppt_第5页
已阅读5页,还剩68页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第 5 章 Java的线程,2019/4/17,Java面向对象程序设计教程,2,主要内容,5.1 线程的概念与POSIX标准 5.1.1 线程的概念 5.1.2 线程的POSIX标准 5.2 多线程的Java实现 5.2.1 线程的创建方法 5.2.2 线程的状态 5.3 互斥线程间的同步机制 5.3.1 多线程带来的冲突问题 5.3.2 共享资源合理使用的实现 5.3.3 按同步协调程度划分的线程间的关系 5.4 java.util.concurrent包简介,5.1 线程的概念与POSIX标准,2019/4/17,Java面向对象程序设计教程,4,线程的概念,线程其实是控制线程(Thread of control)的简写。 控制线程就是程序运行时的路径,是在一个程序中与其它控制线程无关的能够独立运行的代码片段。 与线程有关的几个名词: 进程与线程 并发性与并行性 异步与同步,2019/4/17,Java面向对象程序设计教程,5,基于进程的多任务处理环境,进程是重量级的内核级实体,需要分配它们自己独立的地址空间:包括有虚拟内存映射、文件描述符、用户ID等,并且每个进程都有属于自己的这些集合。用户的程序要访问进程结构中的数据、查询或改变状态,唯一方法是通过系统调用。进程间通信和转换是昂贵和受限的。,2019/4/17,Java面向对象程序设计教程,6,基于线程的多任务处理环境,线程是轻量级实体,由寄存器、堆栈和某些数据组成。进程结构的其余部分由所有的线程所共享:如地址空间、文件描述符等它们共享相同的地址空间并且共同分享同一个进程。线程间通信是便宜的,线程间的转换也是低成本的。,2019/4/17,Java面向对象程序设计教程,7,线程并发,并发性(Concurrency)是两个或多个线程(或传统的进程)可以同时在执行代码之中;可以是相同的代码,也可以是不同的代码。这些线程可以一次执行,也可以多次执行,即一个已开始执行但被中断,而另外一个已开始了。 但在给定的时间点上,只有一个在CPU在处理一个线程 。,2019/4/17,Java面向对象程序设计教程,8,线程并行,并行性(Parallelism)是针对多处理器环境而言的,是指两个或多个线程真正同时运行在不同的CPU上。 在多处理器机上,很多不同的线程可以并行运行,或者说是同时运行。,2019/4/17,Java面向对象程序设计教程,9,异步与同步,异步世界需要处理同步业务 有3个人在3个收银台前结帐 3个人结帐是异步的 每个人信用卡在银行业务处理时需保证同步,2019/4/17,Java面向对象程序设计教程,10,线程的POSIX标准,5.2 多线程的Java实现,2019/4/17,Java面向对象程序设计教程,12,主线程,通过调用Thread类的currentThread方法来查看主线程: Thread.currentThread() 举例:MainThread.java,2019/4/17,Java面向对象程序设计教程,13,创建线程有两种方式,通过直接扩展Thread类来直接创建线程: public class RacingThread extends Thread new RacingThread (10, 1000).start() 举例: RacingThread.java , AnimalWorld.java 通过设计一个类,使之实现java. lang. Runnable接口,再把该接口作为参数传递给Thread类的构造方法后间接创建线程: public class RacingRunnable implements Runnable new Thread(new RacingRunnable (10, 1000).start() 举例:RacingRunnable.java,AnimalWorld.java,2019/4/17,Java面向对象程序设计教程,14,采用间接创建线程的原因,第一个理由是我们并不改变线程本身的性质,仅覆盖run方法,并没有增加新的功能,因此将Thread扩展子类并不恰当,这不太符合类扩展规范。 第二个理由是:如果实现Runnable接口,它可能使我们所设计的类扩展其它类型而变得更为有用。,2019/4/17,Java面向对象程序设计教程,15,start方法与run方法组合实现线程并发,覆盖或实现run方法 start方法一般只用来触发线程,把线程的内容放在这个方法体中不太规范,而且这样做实际上线程不会竞争运行。 如果直接调用run方法,线程也不会竞争运行,必须通过start方法间接调用run方法。 举例:ConcurrentUnavailable.java,2019/4/17,Java面向对象程序设计教程,16,Thread类一些方法使用的例子,线程优先级:PriorityTest.java 创建守护线程:DaemonTest.java 线程列表:ThreadList.java 线程组信息:ThreadGroupTest.java,2019/4/17,Java面向对象程序设计教程,17,线程的状态,2019/4/17,Java面向对象程序设计教程,18,与线程所处状态有关的方法举例,join方法的例子:JoinTest.java yield方法的例子:YieldTest.java interrupt方法的例子:InterruptTest.java,5.3 互斥线程间的同步机制,2019/4/17,Java面向对象程序设计教程,20,多线程带来的冲突问题,实例变量也是共享的 举例: ThreadSharedData.java 使用volatile关键字通知线程及时取得共享变量的更新值 共享资源使用冲突,银行业务中共享资源冲突示意,2019/4/17,Java面向对象程序设计教程,21,举例:AccountSimulator.java,2019/4/17,Java面向对象程序设计教程,22,共享资源合理使用的实现,使用同步方法 调用被synchronized关键字修饰的方法 使用同步代码块 synchronized(obj) / statements to be synchronized ,2019/4/17,Java面向对象程序设计教程,23,讨论:同步对象锁的有效作用域,类本身: synchronized(TransferManager.class) 静态对象: static Object obj=new Object(); synchronized(obj) 实例对象: synchronized(this) 见AccountSimulator.java,讨论:同步对象锁的有效作用域,举例:ObjectLockSample.java,2019/4/17,Java面向对象程序设计教程,24,2019/4/17,Java面向对象程序设计教程,25,思考,在AccountSimulator.java例子中为什么synchronized(this) 无法上锁以保证同步?,TransferManager tm1=new TransferManager(checking, savings); TransferManager tm2=new TransferManager(savings, checking); Thread t1=new Thread(tm1); Thread t2=new Thread(tm2); t1.start(); t2.start();,在线程中使用不同的实例对象,若用this,实际上两个线程分别使用一个对象锁。,2019/4/17,Java面向对象程序设计教程,26,思考,如果要求使用synchronized(this) 也能保证同步,程序应如何改动?,TransferManager tm1=new TransferManager(checking, savings); TransferManager tm2=new TransferManager(savings, checking); Thread t1=new Thread(tm1); Thread t2=new Thread(tm1); t1.start(); t2.start();,让线程使用相同的实例对象,则用this时,两个线程使用一个对象锁。,使用同步方法,同步方法就是用synchronized关键字修饰的方法。当一个线程在一个同步方法内部,所有试图调用该实例同一个方法或其它同步方法的其它线程必须等待。拥有对象锁的线程从同步方法中返回后,即退出对象锁,并把控制权让给其它等待的线程。 静态方法也可以声明为同步。静态同步方法要求为相应的类提供Class对象的锁。两个线程不能同时执行同一个类的静态方法,就像两个线程不能同时执行同一个对象的非静态同步方法。如果静态数据在线程间共享,那么对它的访问就必须利用静态同步方法进行保护。 SynchronizedMethod.java,2019/4/17,Java面向对象程序设计教程,27,同步方法和同步代码块的比较,尽管在创建的类的内部创建同步方法是获得同步的简单和有效的方法,但是,因为它的对象锁的作用域可能太大,有可能引起死锁。同时,同步方法中可能包含了不需要进行同步的代码块,降低了程序的运行效率。因此,我们应该首选采用同步代码块的设计方式。,2019/4/17,Java面向对象程序设计教程,28,2019/4/17,Java面向对象程序设计教程,29,讨论:同步导致的死锁问题,死锁发生在当两个线程对两个同步对象有循环依赖关系时。 例如,假定一个线程进入了对象X的对象锁而另一个线程进入了对象Y的对象锁。如果X的线程试图调用Y的同步方法,它将像预料的一样被锁定。而Y的线程同样希望调用X的一些同步方法,线程永远等待,因为为到达X,必须释放自己的Y的锁定以使第一个线程可以完成。 举例:DeadLock.java,2019/4/17,Java面向对象程序设计教程,30,按同步协调程度划分的线程间的关系,不相关的线程 相关但不需要同步的线程 互斥线程 交互式互斥线程,2019/4/17,Java面向对象程序设计教程,31,不相关的线程:Drinker.java,2019/4/17,Java面向对象程序设计教程,32,相关但无需同步线程:Kid.java,2019/4/17,Java面向对象程序设计教程,33,互斥线程:Customer.java,2019/4/17,Java面向对象程序设计教程,34,交互式的互斥线程:Consumer.java,2019/4/17,Java面向对象程序设计教程,35,交互式互斥线程使用的wait/notify机制,wait方法意味着,即使线程拥有锁,由于得不到期望的数据,因无法做进一步的处理,也只能放弃锁,使线程处于等待状态,而让另一个线程继续工作。 notify方法可以通知位于等待队列中的任何一个线程,但不一定按照FIFO的顺序进行而是遵循JVM的调度。 notify与notifyAll方法之间的差别是: notifyAll方法将唤醒等待当前对象的所有线程,对于所有读取同一信息或者等待同一答案的消费者等待队列而言,这种方法是恰当的。 调用wait/notify的方法必须声明为synchronized,否则将引发运行时异常java.lang.IllegalMonitorStateException。,多线程处理事务中调用notifyAll方法,2019/4/17,Java面向对象程序设计教程,36,PickerPool.java,java.util.concurrent包简介,并发编程在项目开发中很常用。在JDK1.5之前,这些工作通常需要由程序员自己完成代码实现。而JDK1.5中包含的java.util.concurrent很好地解决了这些问题,为我们提供了实用的并发程序模型,其中包括几个小的标准化可扩展框架,以及一些提供有用功能的类。 举例:BlockingQueueSample.java,2019/4/17,Java面向对象程序设计教程,37,第 6 章 Java的输入/输出,2019/4/17,Java面向对象程序设计教程,39,主要内容,6.1 流输入/输出类的层次结构 6.1.1 流的概念 6.1.2 字节流 6.1.3 字符流 6.1.4 输入输出类的分类 6.1.5 标准流及其重定向 6.1.6 IOException及其子类 6.2 输入/输出流类的应用 6.2.1 输入/输出流类的一般例子 6.2.2 典型的输入/输出流类的组合应用 6.2.3 格式化输出 6.3 数据持久化 6.3.1 对象串行化 6.3.2 XML文件的输入输出 6.3.3 JDBC入门 6.4 文件类的应用 6.4.1 File类 6.4.2 File类应用举例,6.1 流输入/输出类的层次结构,2019/4/17,Java面向对象程序设计教程,41,流的概念,流(Stream)是有序的数据序列,它有源(输入流)与目的(输出流)。 java.io包使用术语流定义I/O(输入/输出)。该包有两个主要的部分:字符流(Character stream)和字节流(Byte stream)。 基于文本的I/O都是一些人们能够阅读的字符(比如说程序的源代码),而基于数据的I/O是二进制(比如说表示图像的位图)。 字节流被称作输入流(Input stream)或输出流(Output stream),而字符流被称作Reader或Writer。 字节流不能正确携带字符,一些与字符相关的流在字节流里是没有意义的 。,2019/4/17,Java面向对象程序设计教程,42,java.io包里的类和接口分类,普通的用于建立不同字节和字符流类型的类输入输出流、Reader、Writer和在它们之间进行转换的类。 定义不同类型流的范围过滤流、缓冲流、管道流以及一些流的具体实例。 读写基本值和字符串数据流的类和接口。 一个以系统无关的方式与文件进行交互的类和接口。 形成对象串行化(Object serialization)机制的类和接口将对象传递到字节流,或从一个字节流中读取数据,重新组建对象。,2019/4/17,Java面向对象程序设计教程,43,java.io包里的字节流,2019/4/17,Java面向对象程序设计教程,44,InputStream及其子类的推荐用法,当需要输入ASCII正文或者二进制数值时,应当使用InputStream类。 根据输入源,选用FileInputStream或某个getInputStream方法。 可以有选择行地使用任意数量的InputStream过滤器、缓冲区、扩展器、编码器等子类,然后再上层包装DataInputStream类,并使用它的read方法执行输入。如果需要读入对象而非普通数据,则应当使用ObjectInputStream类。 如果需要使用缓冲技术,应当直接包装FileInputStream类,以便尽可能早地让所有的类都采用缓冲技术。,2019/4/17,Java面向对象程序设计教程,45,java.io的字符流,2019/4/17,Java面向对象程序设计教程,46,转换流,转换流使用的类InputStreamReader和OutputStreamWriter实现了Unicode相同指定编码的字节流,或者本机系统的默认编码的字节流之间的转换。,2019/4/17,Java面向对象程序设计教程,47,输入输出类的分类,文件I/O :FileInputStream 内存缓冲区I/O :BufferedInputStream 存取I/O :DataInputStream 管道I/O :PipedInputStream 过滤器I/O :FilterInputStream,2019/4/17,Java面向对象程序设计教程,48,标准流及其重定向,System.out是标准的输出流,默认情况下,它是一个控制台。 System.in是标准输入流,默认情况下,它指的是键盘。 System.err指的是标准错误流,它默认是控制台。 这些流可以重定向到任何兼容的输入/输出设备。 举例:RedirectSample.java,2019/4/17,Java面向对象程序设计教程,49,IOException及其子类,在java.io中,每一个特定的I/O错误都是用异常IOException及其子类来报告的。 最常见的I/O异常有FileNotFoundException、EOFException、InterruptedIOException、UTFDataFormatError等。,6.2 输入/输出流类的应用,2019/4/17,Java面向对象程序设计教程,51,输入/输出流类的一般例子,在使用输入输出流类时,有两个语句总是要注意的: 一是导入java.io包(import java.io.*;); 二是对IOException异常的处理,一般是在调用的方法的声明时“throws IOException”,当然也可以用try-catch语句进行异常处理。 直接读取标准输入流的用法: InputStreamDemo.java 管道流的使用: PipeIODemo.java,2019/4/17,Java面向对象程序设计教程,52,典型的输入/输出流类的组合应用,标准输入输出: StandardIODemo.java 读写顺序文件:FileIODemo.java 读写二进制文件:BinaryIODemo.java 读写随机文件:RandomIODemo.java,2019/4/17,Java面向对象程序设计教程,53,RandomAccessFile类的文件访问控制权限,“r“ 只读,如果试图进行写操作将引发异常IOException。 “rw“ 可读可写,如果文件不存在将会先创建该文件。 “rws“ 文件可读可写,并且要求每次更改文件内容或元数据时同步写到存储设备中。 “rwd“ 文件可读可写,并且要求每次更改文件内容时同步写到存储设备中。,格式化输出,格式化输出的printf( )方法和format( )方法 Formatter类的format( )方法 格式字符串的语法 转换类型的定义 标识的定义 宽度的定义 精度的定义 参数索引的定义 举例:FormatSample.java,2019/4/17,Java面向对象程序设计教程,54,6.3 数据持久化,2019/4/17,Java面向对象程序设计教程,55,2019/4/17,Java面向对象程序设计教程,56,对象串行化,把一个对象的表示转化为字节流的过程称为串行化(Serialization),而从字节流中把对象重建出来即是反串行化(Deserialization)。 关键字transient描述的是临时的变量,它为被串行化的数据提供了一个语言级的标记数据方法。 默认的串行化过程是将既不是transient也不是static的对象的每个域变量串行化。基本类型和字符串是用DataOutputStream中的编码写的,对象被ObjectOutputStream的writeObject方法串行化。 举例:ObjectSerialization.java,2019/4/17,Java面向对象程序设计教程,57,讨论,在ObjectSerialization.java 文件中改变变量前面的关键字( 增删transient或static ),观察输出结果及文件data.ser 大小的变化。 在ObjectSerialization.java 文件中,如果使readObject和writeObject中定义的结构顺序不一致,将导致什么结果?,XML文件的输入输出,Java为编程提供了一种与平台无关的语言,XML为数据交换提供了一种与平台无关的语言。对于构建基于Web的应用,Java和XML有许多相似的特性,如平台无关性、可扩展性、可重用性和全球语言(Unicode)的支持。把Java和XML技术组合在一起产生了更加轻便的数据。,2019/4/17,Java面向对象程序设计教程,58,XML文档结构,XML文档是由一组数据和描述数据的唯一标记组成,包括声明、元素、注释、字符引用和处理命令。 每个XML文档都是从一个XML版本声明开始,其作用是为XML文档匹配合适的解析器。 举例:students.xml,2019/4/17,Java面向对象程序设计教程,59,XML解析标准,SAX提供对文档内容的顺序只读访问,也就是说,SAX没有提供任何修改文档的功能,也不具备随机访问功能。SAX是基于事件的,它把文档的每个部分当作要发送通知的事件。这种方法只是在读取数据时检查数据,因此不需要将数据存储在内存中,占用的系统资源最少。SAX相关的类和接口存放在org.xml.sax包中。 DOM则可以分析、验证和更新XML文档。它把整个文档读取到内存中,用对象层次集合维护。通过修改这个对象集合,可以改变内存中文档的结构与内容,然后可以将修改后的文档保存到指定的文件中。由于DOM是基于信息层次的,因而DOM被认为是基于树或基于对象的。这种方法应用起来非常灵活,但要占用大量内存。DOM相关的类和接口存放在org.w3c.dom包中。,2019/4/17,Java面向对象程序设计教程,60,SAX解析XML文件,SAX提供了一个通用的接口,这个接口使各种XML的解析器可以相互转换。这些支持解析器具有相同的方法,并且可以通过Java的系统设置进行配置。 SAX 2接口已经成为XML应用的世界标准。 举例:SAXSample.java,2019/4/17,Java面向对象程序设计教程,61,DOM解析XML文件,DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。 DOM解析器把XML文档转化为一个包含其内容的树,并可以对树进行遍历,可以很容易的添加和修改树中的元素。 举例:DOMSample.java,2019/4/17,Java面向对象程序设计教程,62,JDBC原理,JDBC(Java Database Connectivity)是一套协议,是Java开发人员和数据库厂商达成的协议,也就是由Sun定义一组接口,由数据库厂商来实现,并规定了Java开发人员访问数据库的方法调用规范。,2019/4/17,Java面向对象程序设计教程,63,JDBC驱动程序的四个类型,JDBC-ODBC桥驱动程序(JDBC-ODBC Bridge) 这种类型的驱动程序通过桥接方式,把JDBC调用转换为ODBC调用。采用这种方式时,必须将ODBC二进制代码加载到使用该驱动程序的每个客户机上。 本地API(Native-API Bridge) 这种类型的驱动程序把客户机API上的JDBC调用转换为Oracle、Sybase、Informix、DB2或其它DBMS的调用。和桥接驱动程序一样,这种方式要求把某些二进制代码加载到每台客户机上。 JDBC中间件驱动程序(JDBC Middleware) 这种类型的驱动程序将JDBC转换为与DBMS无关的网络协议,之后这种协议又被某个服务器转换为一种DBMS协议。中间件能够将它的Java客户机连接到多种不同的数据库上,所用的具体协议取决于提供者。通常,这是最为灵活的JDBC驱动程序,有可能提供适用于Intranet的产品。 纯Java驱动程序(Pure Java Driver) 这种类型的驱动程序将JDBC调用直接转换为DBMS所使用的网络协议。它允许从客户机机器上直接调用DBMS服务器,是Intranet访问的一个很实用的解决方法。由于许多这样的协议都是专用的,因此数据库提供者自己将是主要来源。,2019/4/17,Java面向对象程序设计教程,64,java.sql包和javax.sql包,JDBC被分割为java.sql和javax.sql两个包。 DriverManager类,是一个创建Connection对象的工厂。 Driver接口,定义了驱动程序类的统一执行规范。 Connection接口,定义了不同JDBC驱动类的连接规范。 Statement接口,定义了执行SQL语句和检索结果的方法。 ResultSet接口,用来接收SELECT语句返回的查询结果,类似于集合。,2019/4/17,Java面向对象程序设计教程,65,加载注册与数据库相对应的JDBC驱动Driver类,方法一:以反射方式动态加载 Class.forName(“com.mysql.jdbc.Driver“); 或 Class.forName(“com.mysql.jdbc.Driver“).newInstance( ); 方法二:以new方式进行加载 new com.mysql.jdbc.Driver( ); 方法三:解析执行时通过虚拟机的属性“-D=”进行设置 java -Djdbc.drivers=com.mysql.jdbc.Driver DBSample 其中“DBSample”表示要执行的类文件名。,2019/4/17,Java面向对象程序设计教程,66,常用数据库的JDBC驱动类的全名,MySQL:com.mysql.jdbc.Driver Oracle:oracle.jdbc.driver.OracleDriver DB2:com.ibm.db2.jdbc.app.DB2Driver SQL Server:com.microsoft.jdbc.sqlserver.SQLServerDriver Access(采用JDBC-ODBC桥):sun.jdbc.odbc.JdbcOdbcDriver,2019/4/17,Java面向对象程序设计教程,67,连接与关闭数据库,java.sql包中的DriverManager类提供了一组getConnection方法用来创建Connection对象。它维护实现java.sql.Driver接口JDBC驱动类列表,提供基于用户给出的JDBC URL的数据库连接。 JDBC URL告诉DriverManager希望连接的数据库引擎,为DriverManager建立数据库连接时提供足够的信息。JDBC URL的标准语法为: jdbc: 其中protocol表示主要协议;subprotocol表示子协议,即驱动程序名称;data source identifier表示数据源信息,如数据库名、数据库用户及密码等。数据源信息对于不同的数据库有不同的格式。 数据库资源并不会自动释放,因此当不使用数据库时,应调用Connection对象的close方法,进行必要的关闭操作。,2019/4/17,Java面向对象程序设计教程,68,常用数据库连接的一般格式,MySQL数据库连接 String url = “jdbc:mysql:/localhost:3306/joopDemo“; String user =“root“; String password = “joop“; Connection conn = DriverManager.getConnection(url,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论