《JAVA并发编程实践》读书笔记(一)

《JAVA并发编程实践》读书笔记(一)

2016年8月1日,“妮妲”冲击广东,全市放假1天。托“妮妲”的福,终于有空将近期的阅读整理一下。
最近利用业余时间重读了Brian Goetz的书,觉得受益匪浅。以前一知半解的概念和用法都在这次阅读中得到了答案。

1.并发简史
并发随操作系统的发展而发展起来,操作系统为各个独立执行的进程分配各种资源,包括内存、文件句柄以及安全证书等,不同的进程间可以通过一些粗粒度的通讯机制来交换数据,包括:套接字、信号处理器、共享内存、信号量以及文件等。并行能力加入到操作系统,主要是基于以下原因:资源利用率公平性以及便利性。同时,上述原因也促使了线程的出现。
在此稍微复习一下进程与线程的区别。
据“恐龙书”所述,非正式而言,进程是执行中的程序。但程序代码有时称为文本段(或者代码段),进程还包括当前的活动,通过程序处理器的值和处理器寄存器的内容来表示,同时还包括进程的堆栈段(包括临时数据,如函数参数、返回地址和局部变量),数据段(包括全局变量)和(在内存空间中,堆由低地址向高地址生长,栈有高地址向低地址生长)。
这里写图片描述
进程是竞争计算机系统资源的基本单位。它至少包括5种基本状态:
-新的:进程正在被创建。
-运行:指令正在被执行。
-等待:进程等待某个事件的发生(如I/O完成或收到信号)。
-就绪:进程等待分配处理器。
-终止:进程完成执行。
这里写图片描述
线程是CPU使用的基本单元,由线程ID、程序计数器、寄存器集合和栈组成。与属于统一进程的其他线程共享代码段、数据段和其他操作系统资源(如文件和信号)。

进程与线程的区别在于,从宏观的角度看,进程的过程是线性的。每个进程有其独立的PCB(进程控制块)。当线程切换的时候,其拥有的资源也需要跟着切换。但是线程的改变只代表CPU执行过程的改变,而进程所拥有的资源并没有发生改变。除了CPU外,计算机内的软硬件资源的分配与线程没有关系。线程只能共享它所属进程的资源。与进程控制表和 PCB 相似,每个线程也有自己的线程控制表 TCB ,而这个 TCB 中所保存的线程状态信息则要比 PCB 表少得多,这些信息主要是相关指针用堆栈(系统栈和用户栈),寄存器中的状态数据。进程拥有一个完整的虚拟地址空间,不依赖于线程而独立存在;反之,线程是进程的一部分,没有自己的地址空间,与进程内的其他线程一起共享分配给该进程的所有资源。(http://www.cnblogs.com/way_testlife/archive/2011/04/16/2018312.html

  1. 线程的执行特性。
    线程只有 3 个基本状态:就绪,执行,阻塞。
    线程存在 5 种基本操作来切换线程的状态:派生,阻塞,激活,调度,结束。

  2. 进程通信。
    单机系统中进程通信有 4 种形式:主从式,会话式,消息或邮箱机制,共享存储区方式。
    主从式典型例子:终端控制进程和终端进程。
    会话式典型例子:用户进程与磁盘管理进程之间的通信。

2.利用多线程的好处。
-降低建模的难度
-简化异步事件的处理
-用户界面响应更加灵敏

3.线程带来的风险
-安全性问题(竞争状态的发生)
-活跃性问题(死锁、饥饿、活锁)
-性能问题 (响应、吞吐率过低、资源消耗过高、可伸缩性较低)

4.线程的安全性
线程的安全核心在于管理状态方位操作,特别是对共享(Shared)和可变的(Mutable)状态的访问。状态不仅包括数据,还包括其他依赖对象的域。

Java的主要同步机制是关键字的synchronized, 他提供了一种独占的加锁方式,但“同步”还包括volatile类型变量,显式锁(Explicit Lock)以及原子变量。
线程安全主要是处理两种情况:
1. 原子性(应对竞态条件以及复合操作)
2. 加锁机制
要保持状态的一致性,就需要在单个院子操作中更新所有相关的状态变量。
Java提供了一种内置锁来支持原子性:同步代码块(Synchronized Block)
synchronized(lock){

每个Java对象多可以做一个实现同步的锁,这个锁叫做内置锁(Intrinsic Lock) 或者监视器锁(Monitor Lock),他是一种互斥锁。内置锁是可重入的,“重入”意味着获取锁的操作粒度是“线程”,不是“调用”。对于可能被多个线程同时访问的可变状态变量,在访问他需要持有同一个锁,我们称状态变量由这个锁保护的。对于每个包含多个变量的不变性条件,其中涉及的所有变量都需要由同一个锁来保护。通常,简单些与性能之间存在互相制约因素,在实现某个同步策略的时候,一定不要盲目为了性能而牺牲简单性。当执行时间较长的计算或者无法快速完成的操作时(例如,IO),一定不要持有锁。
3.可见性
加锁的含义不局限于互斥行为,还包括内存的可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。Java使用volatile变量来提供可见性(无法确保原子性)。
4.发布与逸出
注意不要隐式地把this逸出(应该用工厂方法,在工程内新建对象)。
5.线程封闭
仅仅在单线程内部访问数据,就不需要同步,这项技术叫做线程封闭。(也可以用局部变量和ThreadLocal类实现线程封闭)。
-Ad-hoc线程封闭(将公有变量封闭在一个单线程子系统内部)
-局部变量
-ThreadLocal类
6. 使用final变量保证不变性

阅读更多
换一批

没有更多推荐了,返回首页