输入与输出

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

教材学习内容总结

本章主要讲输入与输出。

10.1

  • 若要将数据从来源中取出,可以使用输入串流;若要将数据写入目的地,可以使用输出串流。在java中,输入串流代表对象为java.in.InputStream的实例;输出串流代表对象为java.io.Outputstream的实例。
  • 在来源与目的地都不知道的情况下可以设计一个通用的dump()方法,该方法接受InputStreamOutputStream实例,分别代表读取数据的来源、输出的目的地。
  • 每次从Inputstream读入的数据,都会先置入byte数据,她的read()方法会尝试读入btye的数据,并返回读入的字节。
  • 要将某个文档读入并另存为另一个数据,可以由命令行操作如下java cc.openhome.Copy c:workspaceMain.java C:workspaceMain.txt

10.2

  • FileInputStreamInputStream的子类,主要操作InputStreamread()抽象方法;FIleOutputStreamOutputStream的子类,主要操作其write()的操作方法
  • 可以使用SystemsetIn()方法指定InputStream实例,重新指定标准输入来源
  • ByteArrayInputStreamInputStream的子类,可以指定byte数据创建实例,主要操作其read()抽象方法;ByteArrayOutputStreamOutputStream的子类,主要操作其write() 的操作方法

10.3

  • 串流装饰器本身并没有改变InputStreamOutputStream的行为,只是在得到数据之后,再做一些加工处理。
  • BufferedInputStreamBufferedOutputStream主要在内部提供缓冲区功能。
  • DataInputStreamDataOutputStream主要提供读取、写入java基本数据类型的方法,会自动在指定的类型与字节之间转换。

10.4

  • Reader.Writer也有一些装饰器类可供使用,如果串流处理的字节数据,实际上代表某些字符的编码数据,而你想要将这些字节数据转换为对应的编码字符,可以使用InputStreamReaderOutputStreamWriter
  • 若要使用CharUtil.dump()读入文档、转为字符串并显示在文本模式中。

10.5

  • 如果处理串流字节数据,将这些字节数据转换为对应的编码制度,可以使用InputStringReader、InputStringWriter打包。
  • BufferedReaderBufferedWriter可对ReaderWriter 提供缓冲区,
  • printWriterPrintStream处理可以对OutputStream打包之外,Printwriter还可以对writer进行打包,提供print()println()format()等方法。

11.1线程

  • 单线程程序:启动的程序从 main() 程序进入点开始至结束只有一个流程
  • 多线程程序:程序有多个流程
  • 课本代码运行截图:

11.2ThreadDaemon

  • Thread:如果想要加装主线程,就要创建 Thread 实例,要启动额外的主线程就是调用 Thread 实例的 start() 方法

  • 额外线程执行流程的进入点,有两种方式:可以定义在 Runnablerun() 方法中继承 Thread 类,重新定义run()方法,主线程会从 main() 方法开始执行,直到main()方法结束后停止 JVM。如果主线程中启动了额外线程,默认会等待被启动的所有线程都执行完 run() 方法才中止 JVM;如果一个 Thread 被标示为Daemon线程,在所有的非 Daemon 线程都结束时,JVM 自动就会终止。从 main() 方法开始的就是一个非 Daemin 线程,可以使用 setDaemon() 方法来设定一个线程是否为 Daemon 线程。使用 isDaemon() 方法可以判断线程是否为 Daemon 线程。

  • 在调用 Thread 实例 start() 方法后,基本状态为可执行(Runnable)、被阻断(Blocked)、执行中(Running)。线程看起来像是同时执行,但事实上同一时间点上,一个 CPU 只能执行一个线程,只是CPU会不断切换线程,且切换动作很快,所以看起来像是同时执行。

  • setPriority():线程有其优先权,可使用 ThreadsetPriority() 方法设定优先权,可设定值为1到10,默认是5,超出1到10外的设定值会抛出 IllegalArgumentException

  • 改进效能的方式:运用多线程,当某线程进入 Blocked 时,让另一线程排入 CPU 执行,避免 CPU 空闲下来。

  • interrupt():一个进入 Blocked 状态的线程,可以由另一个线程调用,该线程的 interrupt() 方法,让它离开Blocked 状态。

11.3ThreadGroup

  • 每个线程都属于某个线程群组。每个线程产生时,都会归入某个线程群组,这视线程在那个群组中产生,如果没有指定,则归入产生该子线程的线程群组,也可以自行指定线程群组,线程一旦归入某个群组,就无法再更换。
  • setMaxpriority():设定群组中所有线程最大优先权。
  • activeCount():取得群组的线程数量,enumerate() 方法要传入 Thread 数组,这会将线程对象设定至每个数组索引。
  • uncaughtException():群组中某个线程发生异常而未捕捉时,JVM 会调用此方法进行处理。如果 ThreadGroup 有父 ThreadGroup,就会调用父ThreadGroupuncaughtException() 方法,否则看看异常是否为ThreadDeath实例,若是则什么都不做,若不是则调用异常的 printStrackTrace(),如果必须定义 ThreadGroup 中的线程异常处理行为,可重新定义此方法。
  • uncaughtException() 方法第一个参数可取得发生异常的线程实例,第二个参数可取得异常对象。

11.4synchronized

  • 每个对象都会有个内部锁定,或称为监控锁定。被标示为 synchronized 的区块将会被监控,任何线程要执行 synchronized 区块都必须先取得指定的对象锁定。如果在方法上标示synchronized,则执行方法必须取得该实例的锁定。线程若因尝试执行 synchronized 区块而进入 Blocked,在取得锁定之后,会先回到 Runnable 状态,等待 CPU 排版器排入 Running 状态。javasynchronized 提供的是可重入同步,也就是线程取得某对象锁定后,若执行过程中又要执行 synchronized,尝试取得锁定的对象来源又是同一个,则可以直接执行。

11.5volatile

  • synchronized 要求达到的所标示区块的互斥性与可见性,互斥性是指 synchronized 区块同时间只能有一个线程,可见性是指线程离开 synchronized 区块后,另一线程接触到的就是上一线程改变后的对象状态。
  • 可以在变量上声明 volatile,表示变量是不稳定的、易变的,也就是可能在多线程下存取,这保证变量的可见性,也就是若有线程变动了变量值,另一线程一定可以看到变更。被标示为 volatile 的变量,不允许线程快取,变量值的存取一定是在共享内存中进行。
  • volatile 保证的是单一变数的可见性,线程对变量的存取一定是在共享内存中,不会在自己的内存空间中快取变量,线程对共享内存中变量的存取,另一线程一定看得到。

11.6等待与通知

  • wait()notify()notifyAll()Object 定义的方法,可以通过这三个方法控制线程释放对象的锁定,或者通知线程参与锁定竞争。
  • wait():执行 synchronized 范围的程序代码期间,若要调用锁定对象的 wait() 方法,线程会释放对象锁定,并进入对象等待集合而处于阻断状态,其他线程可以竞争对象锁定,取得锁定的线程可以执行 synchronized 范围的程序代码。wait() 可以指定等待时间,时间到之后线程会再次加入排班,如果指定时间为0或不指定,则线程会持续等待,只到被中断或是告知可以参与排班。
  • noyify():被竞争锁定的对象调用 noyify() 时,会从对象等待集合中随机通知一个线程加入排班,再次执行 synchronized 前,被通知的线程会与其他线程共同竞争对象锁定。
  • notifyAll():如果调用 notifyAll(),所有等待集合中的线程都会被通知参与排班,这些线程会与其他线程共同竞争对象锁定。

11.7LockReadWriteLock Condition

  • Lock 接口主要操作类之一为 ReentrantLock,可以达到synchronized 的作用,也提供额外的功能。想要锁定 Lock 对象,可以调用其 lock 方法,只有取得 Lock 对象锁定的线程,才可以继续往后执行程序代码,要接触锁定,可以调用 Lock 对象的 unlock()
  • Lock 接口还定义了tryLock() 方法,如果线程调用 tryLock() 可以取得锁定会返回 true,若无法取得锁定并不会发生阻断,而是返回 false
  • ReadWriteLock 接口定义了读取锁定与写入锁定行为,可以使用 readLock()writeLock() 方法返回 Lock 操作对象。ReentrantReadWriteLock.ReadLock 操作了Lock 接口,调用其 lock() 方法时,若没有任何 ReentrantReadWriteLock.WriteLock 调用过 lock() 方法,也就是没有任何写入锁定时,就可以取得读取锁定。
  • ReentrantReadWriteLock.WriteLock 操作了 Lock 接口,调用其 lock() 方法时,若没有任何 ReentrantReadWriteLock.ReadLockReentrantReadWriteLock.WriteLock 调用过 lock() 方法,也就是没有任何读取或写入锁定时,才可以取得写入锁定。
  • validate():验证戳记是不是被其他排他性锁定取得了,如果是的话返回 false,如果戳记是 0 也会返回 false .ConditionCondition 接口用来搭配 Lock,最基本的用法就是达到 Objectwait()notify()notifyAll() 方法的作用。
  • signal():要通知等待集合中的一个线程,则可以调用 signal() 方法。
  • signalAll():如果要通知所有等待集合中的线程,可以调用 signalAll()。
  • 一个Condition 对象可代表有一个等待集合,可以重复调用 LocknewCondition(),取得多个Condition 实例,这代表了可以有多个等待集合。

代码调试中的问题和解决过程

书上的代码运行不了,但都能编译通过,这对我们初学者造成不少麻烦,虽然认认真真学完但依然不太会用,目前依然未解决。
上传代码到git


学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第三周 300/600 2/6 20/50
第四周 300/900 2/8 16/66
第五周 300/1200 2/10 16/82
第六周 300/1500 2/12 16/98

参考资料

原文地址:https://www.cnblogs.com/jokebright/p/5375342.html