您的位置:首页 > 编程语言 > Java开发

20145240 《Java程序设计》第六周学习总结

2016-04-10 18:47 405 查看

20145240 《Java程序设计》第六周学习总结

教材学习内容总结

InputStream与OutputStream

10.1.1串流设计的概念

Java将输入/输出抽象化为串流,数据有来源及目的地,衔接两者的是串流对象。

从应用程序角度来看,如果要将数据从来源取出,可以使用输入串流,如果要将数据写入目的地,可以使用输出串流。在Java中,输入串流代表对象为
java.io.Inputstream
实例,输出串流代表对象为
java.io.OutputStream
实例。

dump()
方法接受
InputStream
OutputStream
实例,分别代表读取数据的来源,以及输出数据的目的地。

FileIntputStream
InputStream
的子类,用于衔接文档以读入数据,
FileOutStream
OutputStream
的子类,用于衔接文档以写出数据。

在不使用
InputStream
OutputStream
时,必须使用
close()
方法关闭串流。由于
InputStream
OutputStrem
操作了
java.io.Closeable
接口,其父接口为
java.lang.AutoCloseable
接口。

10.1.2串流继承结构
1.标准输入/输出

可以使用
System
setIn()
方法指定
InputStream
实例,重新指定标准输入来源。

可以使用
System
setOut()
方法指定```printStream````实例,将结果输出至指定的目的地。

2.FileInputStream与FileOutputStream

FileInputStream
InputStream
的子类,可以指定文件名创建实例,一旦创建文档就开启,接着就可用来读取数据。主要操作了
InputSream
read()
抽象方法,可以从文档中读取数据。

FileOutputStream
OutputStream
的子类,可以指定文件名创建实例,一旦创建文档就开启,接着就可以用来写出数据。主要操作了
OnputSream
write()
抽象方法,可以写出数据至文档。

无论
FileInputStream
还是
FileOutputStream
,在读取、写入文档时是以字节为单位,通常会使用一些高阶类进行打包,不使用时都要使用
close()
关闭文档。

3.ByteArryInputStream与ByteArryOutputStream

ByteArryInputStream
InputStrteam
的子类,可以指定
byte
数组创建实例,一旦创建就可将
byte
数组当做数据源进行读取。

ByteArryOutputStream
OutputStream
的子类,可以指定
byte
数组创建实例,一旦创建将
byte
数组当做目的地写出数据。

10.1.3串流处理装饰器

InputStream
OutStream
提供串流基本操作,如果想要为输入/输出的数据做加工处理,则可以使用打包器类。

常用的打包器具备缓冲区作用的
BufferedIutputStream
BufferedOnputStream
,具备数据转换处理的
DataInputStream
DataOutputStream
,具备对象串行化能力的
ObjectInputStream
ObjectOutputStream
等。

10.2字符处理类

10.2.1Reader与Writer继承架构

针对字符数据的读取,
Java SE
提供了
java.io.Reader
类,其抽象化了字符数据读入的来源。

针对字符数据的写入,则提供了
java.io.Writer
类。其抽象化了数据写出的目的地。

-
StringReader
可以将字符串打包,当作读取来源,
StringWriter
则可以作为写入目的地,最后用
toString()
取得所有写入的字符组成的字符串。

FileReader
FileWriter
则可以对文档做读取与写入,读取或写入时默认会使用操作系统默认编码来做字符转换。

在启动
JVM
时,可以指定
-Dfile.encoding
来指定
FileReader
FileWriter
所使用的编码。

eg:Member类可以调用save()储存Member实例本身的数据,文件名为Member的会员号码,调用Member.load()指定会员号码,则可以读取文档中的会员数据。

import java.io.IOException;
import static java.lang.System.out;

public class MemberDemo {
public static void main(String[] args) throws IOException {
Member[] members = {
new Member("B1234", "Justin", 90),
new Member("B5678", "Monica", 95),
new Member("B9876", "Irene", 88)
};
for(Member member : members) {
member.save();
}
out.println(Member.load("B1234"));
out.println(Member.load("B5678"));
out.println(Member.load("B9876"));
}
}


运行结果



10.2.2字符处理装饰器
1.InputStreamReader与OutputStreamWriter

InputStreamReader
OutputStreamWriter
对串流数据打包。

2.BufferedReader与BufferedWriter

BufferedReader
BufferedWriter
可对
Reader
Writer
提供缓冲区作用,在处理字符输入/输出时,对效率也会有所帮助。

3.PrintWriter

PrintWriter
PrintStream
使用上极为类似,不过除了可以对
OutputStream
打包之外,
PrintWriter
还可以对
Writer
进行打包,提供
print()、println()、format()
等方法。

11.1线程

11.1.1线程简介

在java中,如果想在
main()
以外独立设计流程,可以撰写类操作
java.lang.Runnable
接口,流程的进入点是操作在
run()
方法中。

在java中,从
main()
开始的流程会由主线程执行,可以创建
Thread
实例来执行
Runnable
实例定义的
run()
方法。

eg:TortoiseHareRace2.java。

运行结果



10.1.2Thread与Runnable

JVM是台虚拟计算机,只安装一颗称为主线程的CPU,可执行
main()
定义的执行流程。如果想要为JVM加装CPU,就是创建
Thread
实例,要启动额外CPU就是调用
Thread
实例的
start()
方法,额外CPU执行流程的进入点,可以定义在
Runnale
接口的
run()
方法中。

撰写多线程程序的方式:

1.将流程定义在
Runnable
run()
方法中。

2.继承
Thread
类,重新定义
run()
方法。

操作
Runnable
接口的好处就是较有弹性,你的类还有机会继承其他类。若继承了
Thread
,那该类就是一种
Thread
,通常是为了直接利用
Thread
中定义的一些方法,才会继承
Thread
来操作。

11.1.3线程生命周期
1.Daemon线程

主线程会从
main()
方法开始执行,直到
main()
方法结束后停止JVM。

如果主线程中启动了额外线程,默认会等待被启动的所有线程都执行完
run()
方法才中止JVM。

setDeamon()
方法用来设定一个线程是否为Daemon线程。

如果没有使用
setDeamon()
设定为
true
,则程序会不断的输出
Orz
而不终止。

isDaemon()
方法可以判断线程是否为
Daemon
线程。

运行结果



2.Thread基本状态图

在调用
Thread
实例
start()
方法后,基本状态为可执行(Runnable)、被阻断(Blocked)、执行中(Running)。

eg:DaemonDemo.java。

运行结果



eg:若不使用setDeamon()方法。

运行结果



3.安插线程

当线程使用
join()
加入至另一个线程时,另一个线程会等待被加入的线程工作完毕,然后在继续它的动作,
join()
的意思表示将线程加入称为另一个线程的流程中。

4.停止线程

线程完成
run()
方法后,就会进入
Dead
,进入
Dead
的线程不可以再次调用
start()
方法,否则会抛出
IllegalThreadStateException


eg:InterruptedDemo.java。

运行结果



11.1.4关于ThreadGroup

获取目前线程所属线程群组名:
Thread.currentThread().getThreadGroup().getName()


ThreadGroup
的某些方法,可以对群组中所有线程产生作用。
interrupt()
方法可以中断群组中所有线程,
setMaxPriority()
方法可以设定群组中所有线程最大优先权。
activeCount()
方法获取群组的线程数量 。

未捕捉异常会由线程实例
setUncaughtExceptionHandler()
设定的
Thread.UncaughtExceptionHandler
实例处理之后是线程
ThreadGroup
,然后是默认的
Thread.UncaughtExceptionHandler


11.1.5synchronized与volatile
1.使用synchronized

每个对象都会有个内部锁定,或称为监控锁定。被标示为
synchronized
的区块将会被监控,任何线程要执行
synchronize
区块都必须先取得指定的对象锁定。

java的
synchronize
提供的是可重入同步,也就是线程取得某对象锁定后,若执行过程总又要执行
synchronize
,尝试取得锁定的对象来源又是同一个,则可以直接执行。

由于线程无法取得锁定时会造成阻断,不正确地使用
synchronize
有可能造成效能低下,另一个问题则是死结。

eg:ThreadGroupDemo2.java。

运行结果



2.使用volatile

synchronized
要求达到的所标示区域的互斥性和可见性。互斥性是指
synchronized
区块同时间只能有一个线程;可见性是指线程离开
synchronized
区块后,另一线程接触到的就是上一线程改变后的对象状态。

可以在变量上声明
volatile
,标示变量是不稳定、易变的,也就是可能在多线程下存取,这保证变量的可见性,也就是若有线程变动了变量值,另一线程一定可看到变更。被标示为
volatile
的变量,不允许线程快取,变量值的存取一定是在共享内存中进行。

volatile
保证的是单一变数的可见性,线程对变量的存取一定是在共享内存中,不会在自己的内存空间中快取变量,线程对共享内存中变量的存取,另一线程一定看得到。

eg:Variable2Test.java。

运行结果



eg:Variable3Test.java。

运行结果



11.1.6等待与通知

wait()、notify()、notifyAll()
Object
定义的方法,可以通过这3个方法控制线程释放对象的锁定,或者通知线程参与锁定竞争。

线程要进入
synchronized
范围前,要先取得指定对象的锁定。执行
synchronized
范围的程序代码期间,若调用锁定对象的
wait()
方法,线程会释放对象锁定,并进入对象等待集合而处于阻断状态。

放在等待集合的线程不会参与CPU排班,
wait()
可以指定等待时间,时间到之后线程会再次加入排班,如果指定时间0或不指定,则线程会持续等待,知道被中断或是告知可以参与排班。

wait()
一定要在条件式成立的循环中执行。

11.2并行API

11.2.1Lock、ReadWriteLock与Condition
1.使用Lock

lock
接口主要操作类之一为
ReentrantLock
,可以达到
synchronized
的作用。

想要锁定
Lock
对象,可以调用其
lock()
方法,只有取得
Lock
对象锁定的线程才可以继续往后执行程序代码,要解除锁定可以调用
Lock
对象的
unclock()


Lock
接口还定义了
tryLock()
方法,如果线程调用
tryLock()
可以取得锁定会返回
true
,若无法取得锁定并不会发生阻断,而是返回
false


2.使用ReadWriteLock

ReadWriteLock
接口定义了读取锁定与写入锁定行为,可以使用
readLock()
、`writeLock()
方法返回
Lock```操作对象。

ReentrantReadWriteLock
ReadWriteLock
接口的主要操作类,
readLock()
方法会返回
ReentrantReadWriteLock.ReadLock
实例,
writeLock()
犯法会返回
ReentrantReadWriteLock.WriteLock
实例。

3.使用StampedLock

StampedLock
类可支持了乐观读取操作。也就是若读取线程很多,写入线程很少的情况下,你可以乐观地认为,写入与读取同时发生的机会很少,因此不悲观的使用哇暖的读取锁定,程序可以查看数据读取之后,是否遭到写入线程的变更,再采取后续的措施。

4.使用Condition

Condition
接口用来搭配
Lock
,最基本用法就是达到
Object的wait()、notify()、notifyAll()
方法的作用。

Condition
await()、signal()、signalAll()
方法,可视为
Object的wait()、notify()、notifyAll()
方法的对应。

11.2.2使用Executor

Runnable
用来定义可执行流程与可使用数据,
Thread
用来执行
Runnable


Runnable
指定给
Thread
创建之用,并调用
start()
开始执行。

定义了
java.util.concurrent.Executor
接口,目的是将
Runnable
指定与实际执行分离。

eg:FutureCallableDemo.java。

运行结果



1.使用ThreadPoolExecutor

线程池这类服务的行为实际上是定义在
Executor
的子接口
java.util.concurrent.ExecutorService
中。

通用的
java.util.concurrent.Executor
newCacheThreadPool()
newFixedThreadPool()
静态方法来创建
ThreadPoolExecutor
实例,程序看起来较为清楚且方便。

2.使用ScheduledThreadPoolExecutor

ScheduledExecutorService
ExecutorService
的子接口,顾名思义,可以让你进行工作排程。

schedule()
方法用来排定
Runnable
Callable
实例延迟多久后执行一次,并返回
Future
子接口
ScheduledFuture
的实例。

对于重复性的执行,可使用
scheduleWithFixedDelay()
scheduleAtFixedRate()
方法。

3.使用ForkJoinPool

ForkJoinPool
与其他的
ExecutorService
操作不同的地方在于,它是闲聊了工作窃取演算,其建立的线程如果完成手边任务,会尝试寻找并执行其他任务建立的资额任务,让线程保持忙碌状态,有效利用处理器的能力。

ForkJoin
框架适用于计算密集式的任务,较不适合用于容易造成线程阻断的场合。

11.2.3并行Collection简介

CopyOnWriteArrayList
操作了
List
接口,这个类的实例在写入操作时,内部会建立新数组,并复制原有数组索引的参考,然后在新数组上进行写入操作,写入完成后,再将内部原参考旧数组的变量参考至新数组。

CopyOnWriteArraySet
操作了
Set
接口,与
CopyOnWriteArrayList
相似。

BlockedQueue
Queue
的子接口,新定义了
put()、take()
方法。

ConcurrentMap
Map
的子接口,其定义了
putIfAbsent()、remove()、replace()
等方法。这些方法都是原子操作。

ConcurrentHashMap
ConcurrentMap
的操作类,
ConcurrentNavigableMap
ConcurrentMap
的子接口,其操作类为
ConcurrentSkipListMap
,可视为支持并行操作的
TreeMap
版本。

本周代码托管截图









学习进度条

代码行数(新增/累积)博客量(新增/累积)学习时间(新增/累积)重要成长
目标5000行30篇400小时
第一周200/2001/220/20
第二周300/5001/330/50
第三周500/10001/435/85
第四周1225/22251/540/125
第五周993/32181/535/160
第六周1360/45782/740/200
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: