20145307陈俊达第六周JAVA学习总结
知识点梳理
第十章节
S1
·若要将数据从来源中取出,可以使用输入串流;若要将数据写入目的地,可以使用输出串流。在java中,输入串流代表对象为java.in.InputStream的实例;输出串流代表对象为java.io.Outputstream的实例。
·在来源与目的地都不知道的情况下可以设计一个通用的dump()方法,该方法接受InputStream与OutputStream实例,分别代表读取数据的来源、输出的目的地。
·每次从Inputstream读入的数据,都会先置入byte数据,她的read()方法会尝试读入btye的数据,并返回读入的字节。
·要将某个文档读入并另存为另一个数据,可以由命令行操作如下java cc.openhome.Copy c:\workspace\Main.java C:\workspace\Main.txt
·可以使用System的setIn()方法指定InputStream实例,重新指定标准输入来源
·FileInputStream是InputStream的子类,主要操作InputStream的read()抽象方法;FIleOutputStream是OutputStream的子类,主要操作其write()的操作方法
·ByteArrayInputStream是InputStream的子类,可以指定byte数据创建实例,主要操作其read()抽象方法;ByteArrayOutputStream是OutputStream的子类,主要操作其write() 的操作方法
·串流装饰器本身并没有改变InputStream和OutputStream的行为,只是在得到数据之后,再做一些加工处理。
·BufferedInputStream与BufferedOutputStream主要在内部提供缓冲区功能。
·DataInputStream与DataOutputStream主要提供读取、写入java基本数据类型的方法,会自动在指定的类型与字节之间转换。
S2
·Reader、Writer也有一些装饰器类可供使用,如果串流处理的字节数据,实际上代表某些字符的编码数据,而你想要将这些字节数据转换为对应的编码字符,可以使用InputStreamReader和OutputStreamWriter
·解析几个常用子类: StringReader可以将字符串打包,当做读取来源,StringWriter可以作为写入目的地,最后toString()取出所有写入的字符组成的字符串。CharArrayReader、CharArrayWriter类似,将char数组当做读取来源以及写入目的地。
·如果处理串流字节数据,将这些字节数据转换为对应的编码制度,可以使用 InputStringReader、InputStringWriter打包。
·BufferedReader、BufferedWriter可对Reader、Writer提供缓冲区
·printWriter与PrintStream处理可以对OutputStream打包之外,Printwriter还可以对writer进行打包,提供print()、println()、format()等方法。
第十一章节
S1
•单线程程序:启动的程序从 main() 程序进入点开始至结束只有一个流程
•多线程程序:程序有多个流程
•在 java 中,从 main() 开始的流程会由主线程执行
•Thread:如果想要加装主线程,就要创建 Thread 实例,要启动额外的主线程就是调用 Thread 实例的 start() 方法
•额外线程执行流程的进入点,有两种方式:可以定义在 Runnable 的 run() 方法中继承 Thread 类,重新定义 run() 方法
•Daemon 线程:
•主线程会从 main() 方法开始执行,直到 main() 方法结束后停止 JVM
•如果主线程中启动了额外线程,默认会等待被启动的所有线程都执行完 run() 方法才中止 JVM
•如果一个 Thread 被标示为 Daemon 线程,在所有的非 Daemon 线程都结束时,JVM 自动就会终止
•从 main() 方法开始的就是一个非 Daemin 线程,可以使用 setDaemon() 方法来设定一个线程是否为 Daemon 线程
•使用 isDaemon() 方法可以判断线程是否为 Daemon 线程
•Thread 基本状态图
•在调用 Thread 实例 start() 方法后,基本状态为可执行(Runnable)、被阻断(Blocked)、执行中(Running)
•线程看起来像是同时执行,但事实上同一时间点上,一个 CPU 只能执行一个线程,只是 CPU 会不断切换线程,且切换动作很快,所以看起来像是同时执行
•setPriority():线程有其优先权,可使用 Thread 的 setPriority() 方法设定优先权,可设定值为1到10,默认是5,超出1到10外的设定值会抛出 IllegalArgumentException
•数字越大优先权越高,排版器越优先排入 CPU,如果优先权相同,则输流执行
•改进效能的方式:运用多线程,当某线程进入 Blocked 时,让另一线程排入 CPU 执行,避免 CPU 空闲下来
•interrupt():一个进入 Blocked 状态的线程,可以由另一个线程调用,该线程的 interrupt() 方法,让它离开 Blocked 状态
•安插线程
•join():如果A线程正在运行,流程中允许B线程加入,等到B线程执行完毕后再继续A线程流程,则可以使用 join() 方法完成这个需求
•停止线程
•线程完成 run() 方法后,就会进入 Dead ,进入 Dead 的线程不可以再次调用 start() 方法,否则会抛出 IllegalThreadStateException
•如果要停止线程,最好自行操作,让线程跑完应有的流程,而非调用 Thread 的 stop() 方法
•stop():直接调用 Thread 的 stop() 方法,将不理会所设定的释放、取得锁定流程,线程会直接释放所有已锁定对象,这有可能使对象陷入无法预期状态
•ThreadGroup
•每个线程都属于某个线程群组
•每个线程产生时,都会归入某个线程群组,这视线程在那个群组中产生,如果没有指定,则归入产生该子线程的线程群组,也可以自行指定线程群组,线程一旦归入某个群组,就无法再更换
•setMaxpriority():设定群组中所有线程最大优先权
•enumerate():一次取得群组中所有线程:
Thread[] threads = new Thread[threadGroup1.activeCount()]; threadGroup1.enumerate(threads);
•activeCount():取得群组的线程数量,enumerate() 方法要传入 Thread 数组,这会将线程对象设定至每个数组索引
•uncaughtException():群组中某个线程发生异常而未捕捉时,JVM 会调用此方法进行处理。如果 ThreadGroup 有父 ThreadGroup,就会调用父 ThreadGroup 的 uncaughtException() 方法,否则看看异常是否为 ThreadDeath 实例,若是则什么都不做,若不是则调用异常的 printStrackTrace(),如果必须定义 ThreadGroup 中的线程异常处理行为,可重新定义此方法
•uncaughtException() 方法第一个参数可取得发生异常的线程实例,第二个参数可取得异常对象
•在JDK5 之后,如果 ThreadGroup 中的线程发生异常,uncaughtException() 方法处理顺序为:
•如果 ThreadGroup 有父 ThreadGroup,就会调用父 ThreadGroup 的 uncaughtException() 方法
•否则,看看 Thread 是否使用 setUncaughtExceptionHandler() 方法设定 Thread.Uncaught-ExceptionHandler 实例,有的话就会调用其 uncaughtException() 方法
•否则,看看异常是否为 ThreadDeath 实例,若“是”则什么都不做,若“否”则调用异常的 printfStractTrace()
•synchronized
•每个对象都会有个内部锁定,或称为监控锁定。被标示为 synchronized 的区块将会被监控,任何线程要执行 synchronized 区块都必须先取得指定的对象锁定
•如果在方法上标示 synchronized,则执行方法必须取得该实例的锁定
•线程若因尝试执行 synchronized 区块而进入 Blocked,在取得锁定之后,会先回到 Runnable 状态,等待 CPU 排版器排入 Running 状态
•java的 synchronized 提供的是可重入同步,也就是线程取得某对象锁定后,若执行过程中又要执行 synchronized,尝试取得锁定的对象来源又是同一个,则可以直接执行
•volatile
•synchronized 要求达到的所标示区块的互斥性与可见性,互斥性是指 synchronized 区块同时间只能有一个线程,可见性是指线程离开 synchronized 区块后,另一线程接触到的就是上一线程改变后的对象状态
•可以在变量上声明 volatile,表示变量是不稳定的、易变的,也就是可能在多线程下存取,这保证变量的可见性,也就是若有线程变动了变量值,另一线程一定可以看到变更。被标示为 volatile 的变量,不允许线程快取,变量值的存取一定是在共享内存中进行
•volatile 保证的是单一变数的可见性,线程对变量的存取一定是在共享内存中,不会在自己的内存空间中快取变量,线程对共享内存中变量的存取,另一线程一定看得到
•等待与通知
•wait()、notify()、notifyAll() 是 Object 定义的方法,可以通过这三个方法控制线程释放对象的锁定,或者通知线程参与锁定竞争
•wait():执行 synchronized 范围的程序代码期间,若要调用锁定对象的 wait() 方法,线程会释放对象锁定,并进入对象等待集合而处于阻断状态,其他线程可以竞争对象锁定,取得锁定的线程可以执行 synchronized 范围的程序代码。wait() 可以指定等待时间,时间到之后线程会再次加入排班,如果指定时间0或不指定,则线程会持续等待,只到被中断或是告知可以参与排班
•noyify():被竞争锁定的对象调用 noyify() 时,会从对象等待集合中随机通知一个线程加入排班,再次执行 synchronized 前,被通知的线程会与其他线程共同竞争对象锁定
•notifyAll():如果调用 notifyAll(),所有等待集合中的线程都会被通知参与排班,这些线程会与其他线程共同竞争对象锁定
•Lock、ReadWriteLock 与 Condition
•Lock 接口主要操作类之一为 ReentrantLock,可以达到synchronized 的作用,也提供额外的功能
•想要锁定 Lock 对象,可以调用其 lock 方法,只有取得 Lock 对象锁定的线程,才可以继续往后执行程序代码,要接触锁定,可以调用 Lock 对象的 unlock()
•Lock 接口还定义了tryLock() 方法,如果线程调用 tryLock() 可以取得锁定会返回 true,若无法取得锁定并不会发生阻断,而是返回 false
•ReadWriteLock
•ReadWriteLock 接口定义了读取锁定与写入锁定行为,可以使用 readLock()、writeLock() 方法返回 Lock 操作对象
•ReentrantReadWriteLock.ReadLock 操作了Lock 接口,调用其 lock() 方法时,若没有任何 ReentrantReadWriteLock.WriteLock 调用过 lock() 方法,也就是没有任何写入锁定时,就可以取得读取锁定
•ReentrantReadWriteLock.WriteLock 操作了 Lock 接口,调用其 lock() 方法时,若没有任何 ReentrantReadWriteLock.ReadLock 或 ReentrantReadWriteLock.WriteLock 调用过 lock() 方法,也就是没有任何读取或写入锁定时,才可以取得写入锁定
•validate():验证戳记是不是被其他排他性锁定取得了,如果是的话返回 false,如果戳记是 0 也会返回 false •Condition
•Condition 接口用来搭配 Lock,最基本的用法就是达到 Object 的 wait()、notify()、notifyAll() 方法的作用
•signal():要通知等待集合中的一个线程,则可以调用 signal() 方法
•signalAll():如果要通知所有等待集合中的线程,可以调用 signalAll()
•一个Condition 对象可代表有一个等待集合,可以重复调用 Lock 的newCondition(),取得多个Condition 实例,这代表了可以有多个等待集合
•Executor
•从JDK5 开始,定义了 java.util.concurrent.Executor 接口,目的是将 Runnable 的指定与实际如何执行分离
•ScheduledExecutorService 的操作类 ScheduledThreadPoolExecutor 为 ThreadPoolExecutor 的子类,具有线程池与排程功能
•并行Collection
•CopyOnWriteArraySet 操作了 List 接口,这个类的实例在写入操作时,内部会建立新数组,并复制原有数组索引的参考,然后在新数组上进行写入操作,写入完成后,再将内部原参考旧数组的变量参考至新数组
•BllockingQueu 是 Queue 的子接口,新定义了 put() 与 take() 等方法,线程若调用 put() 方法,在队列已满的情况下会被阻断,线程若调用 take() 方法,在队列为空的情况下会被阻断
心得体会
每周的内容实在是太多了,每一周都有不会的东西积攒下在,到了第六周我实在受不了了,我决定这周开始天天晚上617看视频从头学,不然这么滚雪球的话,到了期末什么也没学会,白白浪费了时间。那真是讽刺意味十足。