20145325张梓靖 《Java程序设计》第6周学习总结
20145325张梓靖 《Java程序设计》第6周学习总结
教材学习内容总结
- 串流设计 输入串流(将数据从来源取出),代表对象为
java.io.InputStream
实例,输出串流(将数据写入目的地),代表对象为java.io.OutputStream
; InputStream 和 OutputStream 可以用自动关闭资源语法关闭(操作了java.io.Closeable
,其父类为java.lang.AutoCloseable
); FileInputStream 是 InputStream的子类,用于衔接文档以读入数据,FileOutputStream 是OutputStream 的子类,用于衔接文档以读入写出数据。 - 串流继承架构 可以使用 System 的 setIn() 方法指定InputStream 实例,重新指定标准输入来源;可以使用 System 的setOut() 方法指定 PrintStream 实例,将结果输出至指定的目的地;标准输出可以重新导向至文档,只要执行程序时使用 > 将结果导向至指定的文档; FileInputStream 是 InputStream 的子类,可以指定文件名创建实例,一旦创建文档就开启可以读取数据,FileOutputStream 是OutputStream的子类,指定文件名来创建实例,一旦创建文档就开启,接着就可以用来写出数据,不用时都要用 close() 关闭文档,在读取、写入文档时,以字节为单位; ByteArrayInputStream 是 InputStream 的子类,可以指定byte数组创建实例,一旦创建就将byte数组当作数据源进行读取,同理,ByteArrayOutputStream 将 byte 数组当作目的地写出数据。
- 串流处理装饰器 这些类本身并没有改变InputStream和OutputStream行为,只不过在 InputStream 取得数据之后做一些加工处理,或者要输出时做一些加工处理,叫由 OutputStream 真正进行输出,因此称它们为装饰器;创建 BufferedInputStream 和BufferedOutputStream 必须提供 InputStream 和 OutputStream 进行打包,可以使用默认或自定义缓冲区大小; BufferedInputStream 与BufferedOutputStream 主要在内部提供缓冲区功能,操作上与InputStream、OutputStream没有太大区别; DataInptStream 与 DataOutputStream 提供读入、写入Java基本数据类型的方法,会自动在指定的类型与字节间转换; ObjectInputStream 与objectOutputStream 将内存中的对象整个存储下来,之后再读入还原为对象; ObjectInputStream 提供 readObject() 方法将数据读入对象, objectOutputStream 提供 writeObject() 方法将对象写至目的地,可以被这两个方法操作的对象,必须操作
java.io.Serializable
接口(这个接口没有定义任何方法,只是作为标示之用,表示这个对象可串化) - Reader与Writer继承架构
java.io.Reader
类,抽象化了字符数据读入的来源,java.io.Writer
类抽象化了字符数据写出的目的地;Reader、Writer 可以使用尝试自动关闭资源语法;FileReader是一种Reader,主要用于读取文档并将读到的数据转换成字符,StringWriter是一种Writer可以将数据写至StringWriter,使用toString()方法取得字符串,代表所有写入的字符数据。 - 字符处理装饰器 将字节数据转换为对应的编码字符,使用InputStreamReader与OutputStreamWriter对串流数据打包;可以指定编码,没有指定编码则以默认编码来做字符转换;BufferedReader、BufferredWriter 为Reader、Writer提供缓冲区作用;System.in是InputStream实例,可以指定给InputStreamReader创建之用,InputStreamReader是一种Reader,可指定给BufferedReader创建之用;InputStreamReader将System.in读入的字节数据做编码转换,BufferedReader将编码转换后的数据做缓冲处理; PrintWriter 与PrintStream 使用上类似,除了可以对 OutputStream 打包之外,还可以对 Writer 进行打包,提供 prinnt()、println()、format()等方法。
- 线程 可以拥有多个流程,也就是多线程程序如果想在main()以外独立建立流程,可以撰写类操作java.lang.Runnable接口,流程的进入点是操作在run()方法中;从main()开始的流程会由主线程执行,创建Thread实例来执行runnable实例定义的run()方法;要启动线程执行指定流程,必须要调用Thread实例的start()。
- Thread与Runnable 将流程定义在 Runnable 的 run()方法中;继承 Thread 类,重新定义 run()方法。
- 线程生命周期 一个 Thread被标示为 Daemon线程,在所有非Daemon线程都结束时,JVM自动终止;使用 setDaemon()方法来设定一个线程是否为 Deamon线程,使用 isDaemon()方法判断线程是否为 Deamon线程默认所有从 Deamon线程产生的线程也是 Deamon线程;使用 Thread的 setpriority()方法设定优先权,1-10,默认值是5让线程进入 Blocked状态,调用 Thread.sleep()等方法,等待输入/输出线程因输入/输出进入 Blocked状态,在完成输入/输出后,会回到 runnable状态;join()将线程加入另一线程的流程中;线程完成run()方法后,会进入Dead,进入Dead的线程不可以再次调用start()方法。
- ThreadGroup 线程一旦归入某个群组,就无法更换;
java.lang.ThreadGroup
可以管理群组中的线程; interrupt()方法可以中断群组中的所有线程; setMaxpriority()方法可以设定群组中所有线程最大优先权; enumerate()方法可以一次取得群组中所有线程; activeCount()方法取得群组的线程数量; uncaughtException()方法处理某个线程未被捕捉的异常。 - synchronized与volatile 被标示为 synchronized的区块将会被监控,任何线程要执行该区块必须先取得指定的对象锁定;线程尝试执行synchronized区块而进入 Blocked,在取得锁定之后,会先回到Runnable状态,等待排入 Runnning状态; synchronized要求达到的所标示区块的互斥性,与可见性;在变量上声明 volatile,表示变量是不稳定、易变的,可能在多线程下存取,保证变量的可见性。
- ** 等待与通知** 调用锁定对象的 wait()方法,线程释放对象锁定,进入对象等待集合处于阻断状态(不参与CPU排班),其他线程竞争对象锁定执行 synchronized范围的程序代码;wait()可以指定等待时间,时间到之后线程自动加入排班,指定时间为0或不指定,线程会继续等待,直到被中断;调用 notify(),会从对象等待集合中随机通知一个线程加入排班,被通知的线程会与其他线程共同竞争对象锁定;调用notifyAll()会通知等待集合中的线程全部参加排班,这些线程会与其他线程共同竞争对象锁定。
- Lock、ReadWriteLock、Condition Lock接口主要操作类之一为ReentranLock,可以达到 synchronized的作用,也提供额外的功能;锁定 Lock对象,调用其 lock()方法,解除锁定,调用 unlock()方法;trylock() 方法,取得锁定返回true,没取得锁定返回 false; ReadWriteLock 接口定义了读取锁定与写入锁定的行为,ReentrantReadWriteLock是 ReadWriteLock接口的主要操作类;ReadWriteLock 在没有任何读取或写入锁定时,才可以取得写入锁定,可用于悲观读取; Condition接口用来搭配 Lock,最基本用法就是达到Object的wait()、notify()、notifyAll()方法的作用;调用 Lock的newCondition() 取得 Condition操作对象;调用 Lock的 await()将会使线程进入 Condition的等待集合;调用 signal()方法通知等待集合中的一个线程,signalAll()方法通知所有等待集合中的线程。
- Executor
java.util.concurrent.Executor
接口,将Runnable的制定与实际执行分离,定义了 execute()方法;定义在java.util.concurrent.ExecutorService
,需要线程池的功能,可以使用其子类java.util.concurrent.ThreadPoolExecutor
; ExecutorServic e的 shutdown()方法会指定执行的 Runnable都完成后啊,将 ExcutorService 关闭, shutdownNow() 方法可以立即关闭ExcutorService;ScheduledExecutorService为ExecutorService子接口,进行工作排成,schedule()方法用来排定Runnable或Callable实例延迟多久后执行一次,并返回 Future子接口 ScheduleFuture的实例,对于重复性的执行,可使用 scheduleWithFixedDelay()与scheduleAtfixedRate() 方法; scheduleWithFixedDelay()可安排延迟多久首次执行 Runnable,执行完会排定延迟多久再次执行,scheduleAtfixedRate() 依据指定周期排定每次执行的时间,了两种方法上次排定的工作抛出异常,不会影响下次排程的进行。 - 并行Collection简介 CopyOnWriteArrayList 操作了 List接口,复制数组;CopyOnWriteArraySet 操作了 Set接口,适用于很少写入数据,但是迭代器频繁的情况;BlockingQueue 是 Queue的子接口,新定义了 put()和 take()等方法,调用 put()方法,在队列已满的情况下会被阻断,调用 take方法,在队列为空的情况下会被阻断;使用BlockingQueue 的操作 ArrayBlockingQueue类,就不用处理 wait()、notify()等流程。
教材学习中的问题和解决过程
- 问题 p329 建立 Thread,是只有 Thread才可以使用简洁的Lambda表达式方法操作吗?
- 解决过程 1.使用通常即匿名内部类建立 Thread,如下
可以正常输出结果。
2.将 Thread用简洁的Lambda表达式方法操作建立:
可以输出结果。
3.在 Thread用简洁的Lambda表达式方法操作时,直接使用.start方法,其他不做改动。
出现了错误,说明不是一类的不可以放到另一个类里面。
4.只创建 Thread实例,同时使用.start方法:
可以正常输入。
5.自己新建一个类,在主线程中创建此类的匿名内部类,没使用调用方法:
编译成功,但没有结果,说明匿名内部类和一般的建立实例不一样,它并不在建立实例的时候就将方法运行。
6.使用了调用方法:
正常运行。
7.用简洁的 Lambda表达式方法操作建立自己新建的类:
不可以,暂时可以认为用“简洁的Lambda表达式方法操作建立”是 Thread所特有的。
8.又改为使用Lambda表达式(省略new Test):
不可以,错误原因已经写出,是因为不是接口,说明这种省略方式只能对接口进行操作。
9.将原先定义的类改为接口:
可以正常运行。
10.如果接口中有1个以上的方法:
出现了错误,说明这种省略只能是适用在只有唯一方法的接口。
代码调试中的问题和解决过程
每行代码的执行顺序还需要仔细尝试一下,而且每次非Daemon线程执行的时间都是不一的,可以更多的调试代码试试。
代码托管
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 3500行 | 28篇 | 300小时 | |
第一周 | 150/150 | 1/1 | 20/20 | |
第二周 | 100/250 | 1/2 | 22/42 | |
第三周 | 150/400 | 2/4 | 21/63 | |
第四周 | 1000/1400 | 1/5 | 27/90 | |
第五周 | 300/1700 | 1/6 | 22/102 | |
第六周 | 250/1950 | 2/8 | 22/124 |