20145202马超 《Java程序设计》第六周学习总结
进程:是一个正在执行中的程序,每一个进程都有一个执行程序,该顺序是一个执行路径,或者说是一个控制单元。
线程:就是进程中的一个独立的控制单元,线程在控制着进程的执行。
一个进程至少有一线程。
Java VM 启动的时候会有一个java进程java.exe
该进程中至少一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法之中,该线程被称为主线程。
自定义代码中自定义线程:通过对api的查找,java已经提供了对线程这类食物的描述,就Three类。
创建线程的方式:继承Thread类。
1.定义类继承Thread类。
2.复写Thread类中的run方法。
3.调用线程的start方法。
为什么要覆盖run方法?
Thread类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。
也就是说Thread类中的run方法,用于存储线程要运行的代码。
将running接口子类对象作为实际参数传递给Thread类的构造函数。
为什么要讲running接口子类传递给Thread的构造函数?
以你为自定义的run方法所属的对象是runnable接口的子类对象,所以要让线程去指定对象的run方法,就必须明确该run方法所属对象。
调用Thread类的start方法开启线程并调用running接口子类run方法
线程间的通讯:
其实就是多个线程在操作同一个资源,但是操作的动作不同。
字符流两个分类:
1.inputsteam
2.outputsteam
流(Stream)是对输入输出的抽象,注意输入输出是相对程序而言的
InputStream与OutputStream
InputStream、OutStream提供串流基本操作,如果想要为输入/输出的数据做加工处理,则可以使用打包器类。常用的打包器具备缓冲区作用的BufferedOutputStream、BufferedInputStream,具备数据转换处理的DataInputStream、DataOutputStream,具备对象串行化能力的ObjectInputStream、ObjectOutputStream等。
write:对空文件写入数据
read:读取单个字符
read(char【】 cbuf):讲字符读入数组
read(char【】 cbuf,int off,int len):讲字符读入数组的某一部分
read(CharBuffer target)试图将字符读入制定的字符缓冲区。
Reader与Writer
Reader、Writer也有一些装饰器类可供使用。如果串流处理的字节数据,实际上代表某些字符的编码数据,而你想要将这些字节数据转换为对应的编码字符,可以使用InputStreamReader、OutputStreamWriter对串流数据打包。BufferedReader、BufferedWriter可对Reader、Writer提供缓冲区作用,在处理字符输入/输出时,对效率也会有所帮助。PrintReader、PrintStream使用上极为类似,不过除了可以对OutputStream打包之外,PrintWriter还可以对Writer进行打包,提供print()、println()、format()等方法。
字符处理装饰器
想要将这些字节数据转换为对应的编码字符,可以使用InputStreamReader、OutputStreamWriter对串流数据打包。
BufferedReader、BufferedWriter可对Reader、Writer提供缓冲区作用,在处理字符输入/输出时,对效率也会有所帮助。
PrintWriter还可以对Writer进行打包,提供print()、println()、format()等方法。
并行API:
基于Thread类和Runnable接口编程很容易实现基本的并行编程任务,但实现复杂的并行程序就会比较困难,因为要详细考虑资源的同步访问以及设计必要数据结构支持同步访问。从Java5后,Java平台提供了java.util.concurrent包以及HighLevelAPI简化并行编程模型,并提供了很多支持同步访问数据结构满足编程需要。
Lock(锁对象):相对与Thread模型的隐式的锁对象,Lock提供了显式的锁操作从而简化应用程序。Executors:提供了一组HighLevelAPI用来执行和管理并行任务。 ConcurrentCollections(并行集合):包含了一组支持并行处理的数据结构,大大简化了并行编程难度。AtomicVariables(原子变量):减少了同步操作并且避免数据不一致。Fork/Join框架:提供了进程操作的支持。
CopyOnWriteArrayList操作了List接口,顾名思义,这个类的实例在写入操作时,内部会建立新数组,并复制原有数组索引的参考,然后在新数组上进行写入操作,写入完成后,再将内部原参考旧数组的变量参考至新数组。对于一个很少进行写入操作,而使用迭代器频繁的情景下,可以使用CopyOnWriteArrayList提高迭代器操作的效率。BlockingQueue是Queue的子接口,新定义了put()与take()等方法,线程若调用put()方法,在队列已满的情况下会被阻断,线程若调用了take()方法,在队列为空的情况下会被阻断。ConcurrentMap是Map的子接口,其定义了putIfAbsent()、remove()、replace()等方法。这些方法都是原子操作。putIfAbsent()在键对象不存在ConcurrentMap中时,才可置入键/值对象,否则返回键对应的值对象。remove()只有在键对象存在,且对应的值对象等于指定的值对象,才将键/值对象移除。replace()有两个版本,其中一个版本是只有在键对象存在,且对应的值对象等于指定的值对象,才将值对象置换,另外一个版本是在键对象存在时,将值对象置换。
单线程程序是从开始到结束只有一个流程:
多线程程序:一个程序拥有多个流程。
撰写多线程程序的方式:操作Runnable接口,在run()中定义额外流程;继承Thread类,在run()中定义额外流程;
差别:操作Runnable接口的好处就是较有弹性,类还有机会继承其他类;若继承了Thread类,那该类就是一种Thread,通常是为了直接利用Thread中定义的一些方法,才会继承Thread来操作。
如果主程序中启动了额外线程,默认会等待被启动的所有线程都执行完run()方法才中止JVM。如果一个Thread被标示为Daemon线程,在所有的非Daemon线程都结束时,JVM自动就会终止。
在调用Thread实例start()方法后,基本状态为可执行(Runnable)、被阻断(Blocked)、执行中(Running)。
线程有其优先权,可使用Thread的setPriority()方法设定优先权,可设定值为1到10,默认是5,超出1到10外的设定值会抛出IllegalArgumentException。数字越大优先权越高,排班器越优先排入CPU,如果优先权相同,则输流执行。
如果A线程正在运行,流程中允许B线程加入,等到B线程执行完毕后再继续A线程流程,则可以使用join()方法完成这个需求。
线程完成run()方法后,就会进入Dead,进入Dead(或已经调用过start()方法)的线程不可以再次调用start()方法,否则会抛出IllegalArgumentException。
如果要停止线程,最好自行操作,让线程跑完应有的流程,而非调用Thread的stop()方法。不仅停止线程必须自行根据条件操作,线程的暂停、重启,也必须视需求操作,而不是直接调用suspend()、resume()等方法。
每个线程产生时,都会归入某个线程群组,这视线程是在哪个群组中产生,如在main()主流程中产生一个线程,该线程会属于main线程群组。如果没有指定,则归入产生该子线程的线程群组,也可以自行指定线程群组,线程一旦归入某个群组,就无法更换群组。
每个对象都会有个内部锁定,或称为监控锁定。被标示为synchronized的区块将会被监控,任何线程要执行synchronized区块都必须先取得指定的对象锁定。
如果在方法上标示synchronized,则执行方法必须取得该实例的锁定。synchronized不只可声明在方法上,也可以描述句方式使用。不正确的使用可能会造成死结。
Java的synchronized提供的是可重入同步,也就是线程取得某对象锁定后,若执行过程中又要执行synchronized,尝试取得锁定的对象又是同一个,则可以直接执行。
执行synchronized范围的程序代码期间,若调用锁定对象的wait()方法,线程会释放对象锁定,并进入对象等待集合而处于阻断状态,其他线程可以竞争对象锁定,取得锁定的线程可以执行synchronized范围的程序代码。
放在等待集合的线程不会参与CPU排班,wait()可以指定等待时间,时间到之后线程会再次加入排班,如果指定时间0或不指定,则线程会持续等待,直到被中断(调用interrupt()或是告知notify())可以参与排班。
被竞争锁定的对象调用notify()时,会从对象等待集合中随机通知一个线程加入排班,再次执行synchronized前,被通知的线程会与其他线程共同竞争对象锁定;如果调用notifyAll(),所有等候集合中的线程都会被通知参与排班,这些线程会与其他线程共同竞争对象锁定。
在使用高级并行API时,Condition接口的操作对象可实现Object的wait()、notify()、notifyAll()功能。
在使用高级并行API时,Future接口的操作对象可以让你在未来取得执行结果。
第十章课后习题:
1.AC
2.BD
3.AC
4.B
5.A
6.B
7.B
8.B
9.D
10.D
第十一章习题:
1.A
2.B
3.B
4.A
5.A
6.D
7.B
8.A
9.B
10.C
遇到的问题:
也不能说是问题应该只能说是麻烦吧,是什么麻烦呢?其实很简单,我看视频上讲的以及书上的知识用两天的时间学完一周的任务并不算是很难,但是问题就在于东西实在是太多,比如现在再让我回想之前的知识以及语法,我就会忘记很多,虽然说java代码肯定是在于一个熟能生巧,但是短时间内接触这么多的思想以及语法概要真的是让人压力很大,我不知道当时上课的时候他们有一周的时间学习这些知识的结果是怎么样的,但如果我想暑假把20周的任务完成的话只能采取两天走一周的方式,代码还是要多敲一些才行,目前我只能是完成书上的题目以及书上课本上有的代码我练一练,在此基础上多把现在学习的和之前学的融合在一起可能是之后的主要任务。
代码托管截图: