20145335郝昊《java程序设计》第6周学习总结
20145335郝昊 《Java程序设计》第6周学习总结
教材学习内容总结
第十章
-
串流(Stream):
数据有来源及目的地,衔接两者的是串流对象。如果要将数据从来源取出,可以使用输入串流;如果要将数据写入目的地,可以使用输出串流。在java中输入串流代表对象为java.io.InputStream,输出串流的代表对象为java.io.OutStream。
-
字节处理类:
-
特点:
- dump()方法接受InputStream和OutputStream是实例,分别代表读取数据的来源,以及输出数据的目的地。
- 在不使用InputStream和OutputStream时,必须使用close()方法关闭串流。
- 每次从InputStream读入的数据,都会先置入byte数组中。
- InputStream的read()方法,每次会尝试读取byte数组的长度,并返回实际读入的字节。
- OutputStream的write()方法,指定要写出byte数组、初始索引与数据长度。
- 标准输入:System.in,是InputStream的实例。可以使用System的setIn()方法指定InputStream实例,重新指定标准输入来源。
- 标准输出:System.out,是OutputStream的实例。可以使用System的setOut()方法指定PrintStream实例,将结果输出至指定的目的地。
- FileInputStream是InputStream的子类,可以指定文件名创建实例,接着就可以用来读取数据。
- FileOutputStream是OutputSream的子类,可以指定文件名创建实例,接着就可以用来写出数据。
- ByteArrayInputStream是InputStream的子类,可以将数组byte当作数据源进行读取。
- ByteArrayOutputStream是OutputStream的子类,可以将数组byte当作目的地写出数据。
- 串流处理装饰器:具有缓冲区作用的BufferedInputStream、BufferedOutputStream。具有数据转化处理作用DataInputStream、DataOutputStream。具有对象串行化能力的ObjectInputStream、ObjectOutputStream。
-
注意:
- 若dump()方法进行InputSream和OutputStream发生错误,则在dump()方法上声明throws,由调用dump()方法的客户端处理。
- 还有个System.err为PrintStream实例,称为标准错误输出串流,它是用来立即显示错误信息。也可以使用System.setErr()指定PrintStram,重新制定标准错误输出串流。
- 无论FileInputStream还是FileOutputStream,不使用的时候都要用close()关闭文档。
- ObjectInputStream提供readObject()方法将数据读入为对象,而ObjectOutputStream提供writeObject()方法发将对象写至目的地,其必须操作java.io.Serializable接口。
-
-
字符处理类
-
特点:
- 针对字符数据的读取有java.io.Reader类和java.io.writer类。
- 在不使用Reader和writer时,必须使用close()方法关闭串流。
- Reader的read()方法,每次尝试读入char数组长度的数据,并返回实际读入的字符数,只要不是-1,就表示读取到字符。
- Writer的write()方法,指定要写出byte数组、初始索引与数据长度。
- 字符处理装饰器:InputStreamReader和OutStreamWriter具有将字节数数据转换为对应的编码字符。BufferedReader和BufferedWriter为数据提供缓冲区的作用,在处理字符输入/输出的时候,对效率也会有所帮助。PrintWriter与PrintStream作用相类似。
-
注意:
- 与处理字节数据相同,dump()方法接受Reader与Writer实例,若发生错误,在dump()方法上声明throws,调由dump()方法的客户端。
- StringReader可以将字符串打包,当作读取来源,StringWriter可以作为写入目的地。
- FileReader、FileWriter可以对文档做读取与写入,读取或写入时默认会使用操作系统默认编码来做字符转换。
-
第十一章
-
线程:
>单线程程序,也就是启动的程序从main()程序进入点开始至结束只有一个流程。有时候需要设计程序可以拥有多个流程,也就是所谓的多线程程序。 >在java中,如果想在main()以外独立设计流程,可以撰写类操作java.lang.Runnable接口,流程的进入点是操作在run()方法中。
-
关于线程
-
Thread与Runnable:
撰写多线程程序方式,除了将流程定义在Runable的run()方法中还有是继承Thread类,重新定义run()方法。 如果创建Thread时候指定Runnable实例,就会由target参考。
-
线程生命周期:
Dameon线程:如果一个Thread被表示为Daemon线程,在所有的非Demon线程都结束时候,JVM会自动终止。从main()方法开始就是一个非Dameon线程,可以使用setDameon()方法来设定一个线程是否为Dameon线程。使用isDameon()方法可以判断线程是否为Dmaeon线程。
Thread基本状态:线程有其优先权,可使用Thread的setPriority()方法设定优先权。有几中方法会让线程进入Blocked状态,一个进入Blocked状态的线程,可以由另一个线程调用该线程的intrerrupt()方法,让他离开Blocked状态。
安插线程:如果线程A正在运行,流程中允许B线程加入,等到B线程执行完毕后再继续A线程流程,可以使用join()方法完成这个需求。
停止线程:线程完成后run()方法后,就会进入Dead,进入Dead的线程不可以再次调用start()方法。如果要停止线程,最好的方法是让它自己跑完应有的流程,而非调用Thread的stop()方法。
-
关于ThreadGroup:
每个线程都属于某个线程群组。若在main()主流中产生一个线程,该线程会属于main线程群组。如果没有指定,则归入产生该子线程的线程群组。也可以自行制定线程群组,线程一点归入某个群组,就无法再更换。
interrupt()方法可以中断群组中所有线程。
setMaxPriority()方法可以设定组群中所有线程最大优先权。
enumerate()方法可以一次取得群组中所有线程。
activeCount()方法取得群组的线程数量。
uncaughtException()方法,群组中某个线程发生异常而未捕捉时,JVM会调用此方法进行处理。其第一个参数可取得发生异常的线程实例,第二个参数可取得异常对象。
-
-
synchronized与volatile:
使用Synchronized,在执行方法必须取得该实例的锁定。简单来说,可以确保某线程执行add(),将add()中定义的流程完整执行,从而避免了ArrayIndexOutOfBoundsException发生。由于线程无法取得锁定时会造成阻断,不正确的使用synchronized有可能造成效能低落,另一问题则是死结。
使用volatile,可在变量上声明volatile,表示变量是不稳定、易变的,也就是可能在多线程下存取,这保证变量的可见性,也就是若有线程变动了变量值,另一线程一定可以看到变更。被标为volatile的变量,不允许线程快取,变量值的存取一定是在共享内存中进行。
-
等待与通知:
wait()、notify()、notifyAll()是Object定义的方法,可以通过这三个方法控制线程释放对象的锁定,或者通知线程参与锁定的竞争。
-
并行API
-
Lock、ReadWriteLock与Condition
使用LockL:lock接口主要操作类之一为ReentrantLock,如果已经有线程取得Lock对象锁定,尝试再次锁定同一Lock对象是可以的。想要锁定Lock对象,可以调用其lock()方法,只有取得lock对象锁定的线程,才可以继续往后执行程序代码,要解除锁定,可以调用Lock对象的unLock()。Lock接口还定义了tryLock()方法,如果线程调用trylock()可以取得锁定会返回true,若无法取得锁定并不会发生阻断,而是返回false。
使用ReadWriteLock:ReadWriteLock接口定义了读取与写入锁定的行为,可以使用readLock()、writelock()方法返回Lock操作对象。ReentrantReadWriteLock是ReadWriteLock主要操作类。
使用StampedLock:,可支持乐观读取操作,也就是若读取的线程很多,写入的线程很少的情况下,可以乐观的认为写入与读取同时发生的机会甚少,因此不悲观的使用完全的读取锁定,程序可以查看数据读取之后,是否遭到写入线程的变化,再采取后续措施。validate()方法用来验证戳记是否被其他排他性锁定取得了,如果是返回false,如果戳记是0也返回false。
使用condition:调用Lock的newCondition()取得Condition操作对象,调用Condition的await()将会使线程进入Condition的等待集合。调用signal()方法通知等待集合中的一个线程。如果要通知所有等待集合中的线程,调用signalAll()方法。
-
使用Executor
java.util.concurrent.Executor接口,目的是将Runnble的指定与实际如何分离。
使用ThreadPoolExecutor:使用java.util.concurrent.Executor的newCashedThreadPool()、newFixedThreadPool()静态方法来创建ThreadPoolExecutor实例。ExecutorService还定义了submit()、invokeAll()、invokyeAny()等方法。
java.util.concurrent.FutureTask是Future的操作类,创建时可以传入Callable操作对象来指定执行的内容。使用ScheduleThreadPoolExecutor:schedule()方法用来排定Runnable或Callable实例延迟多久后执行一次,并返回Future子接口ScheduleFuture的实例;对于重复性的执行,可使用scheduleWithFixedDelay()与scheduleAtFixedRate()方法。
使用ForkJoinPool:主要目的是在解决分而治之的问题。
-
并行Collection简介
CopyOnWriteArrayList:内部会建立新的数组,并复制原有参数索引的参考,在新数组上进行写入操作。
CopyOnWriteArraySet:在使用迭代器操作时会有很好的效率,适用于一个很少进行写入操作。
BlockingQueue定义了put()和take()方法。put()在队列已满的情况下会被阻断。take()在队列为空的情况下会被阻断。
ConcurrentMap定义了putIfAbsent(),其在键对象不存在CouncurrentMap中才可以置入键/值,否则返回键对应的值对象。remove(),其只有在键对象存在,且对应的值对象等于指定的值的对象,才将键/值移除。replace()方法,其中一个只有在键对象存在,且对应的值对象等于指定的值的对象,才将值对象置换;另一个是在键存在的时候,将值对象置换。
ConcurrentHashMap是ConcurrentMap的操作类,ConcurrentNavigable是ConcurrentMap子接口,其操作类为ConcurrentSkipListMap。
教材学习中的问题和解决过程
第十章
-
关于dump()的方法
起初对于这个方法的理解不是很透彻,这个方法的来源是什么?它是继承了哪个类还是操作了某个接口?对于书上给出的并没有限定来源或目的地的真实形式,而是依赖于抽象的InputStream和OutputStream。对于这个答案并不太理解。后来仔细看书后,如果细致的掌握了java中以串流抽象化输入/输出的概念,以及InputStream、OutputStream继承架构后就可以清楚的掌握有关dump()方法的使用,因为对于字符类数据进行处理的时候也需要用到dump()方法。
-
关于串流处理装饰器
>对于这个串流装饰器的意义是什么?为什么要用串流装饰器来装饰数据?后来经过仔细阅读课本后发现,虽然命名为串流装饰器,但实际上也提供了许多其他的方法。是一种类型打包器类。就比如对于字节数据的BufferedInputStream、BufferedOutputStream、DataInputStream、DataOutputStream、ObjectInputStream、ObjectOutputStream。 > >就像运用书上的例子可以,像小水管衔接大水管,由小水管读取数据,再由大水管增加缓冲功能提供一些额外的对数据处理。
第十一章
-
关于线程
>线程的概念在这章由为重要,分不清楚对于Thread和Runnable的区别,看书后分析出了这两个都为java的一个类,而run()方法为Runnable的方法。在编译多线程程序的时候,继承Thread类,重新定义run()的方法。那么是操作Runnable在run()中定义额外流程好,还是继承Thread在run()中定义额外流程好?后来通过看书上的代码,自己的编译,操作Runnable接口的好处是较有弹性,还可以继承其他的类。也便于维护系统。
-
关于Blocked
对于这个Blocked区块的做用,及其存在的意义不太清楚,为什么要有Blocked区块的存在?后来通过仔细看书,分析书上的代码,并结合多线程程序的特点发现Blocked存在的需要为了协调多线程程序的的输出和写入数据的冲突。协助等待CPU排班器排入Running状态。
-
关于并行API
在JDK5之后提供了java.util.concurrent包,可基于其中的API建立更加稳固的并行应用程序。但是为什么不将这个包的方法定义到之前的包中?后来知道了提供更多且高级的功能。提供的功能不仅可以完善原来的需求,也可以提高需求。但是若将这些方法放入到之前的文件中,对于有些低需求的来说反而会占用很大的资源,造成资源浪费。
代码调试中的问题和解决过程
第十章
在调试书上的范例出现了问题。其中是Stream Copy.java文件中其中有一行代码IO.dump但是用Idea编译的时候显示IO有错误。
同上一个问题相似。Stream Download.java文件中IO.dump(src,dest);但是用编译软件也是显示IO有错误。
第十一章
对于书上的Thread DamonDemo.java程序,一开始不能很好的理解用setDemo()方法来设定一个线程是否为Dameon线程,但是通过编译书上的范例就有了很详细的理解。
还有对于方法Thread.sleep()方法让线程进入Blocked状态,对于有其他线程调用该线程的interrupt()方法,存在问题,会抛出InterrupttedException异常对象。在编译书上的范例时候就知道了thread.interrupt();是主线程调用thread的interrupt方法。
本周代码托管截图
以下为本周代码的部分截图,所有代码已经上传并托管到开源中国。
其他(感悟、思考等,可选)
学习java的时间也有较长的一段时间了,渐渐的对于这种学习方式也有了适应,对于所学习到的知识也有了更深层次的理解和认识,对于java还是其他计算机语言的元知识和硬知识有了较为扎实的功底,但是对于这些语言的软知识还存在问题。所学到目前的知识还不能很好很高效的自己完成程序的设计和程序代码的书写。在一些语言的语法运用上也不是很熟练,总是会出现错误越改越多的情况。总之对于java语言的学习还是有很大的方面需要去提高。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 300/500 | 2/4 | 18/38 | |
第三周 | 800/1000 | 3/7 | 20/60 | |
第四周 | 1000/1300 | 1/9 | 19/90 | |
第五周 | 1300/1500 | 2/11 | 20/100 |
参考资料
- Java学习笔记(第8版)
- 《Java学习笔记(第8版)》学习指导
- ...****