1、设计线程安全类的过程

设计线程安全类的过程就是设计对象状态并发访问下线程间的协同机制(在不破坏对象状态变量的不变性条件的前提下)。

(1)构建线程安全类的三个基本要素:

1)找出构成对象状态的所有变量;(确定状态变量的类型(共享、可变的、不可变的),针对不同类型的状态变量采用不同的并发访问策略)

2)找出约束对象状态变量的不变性条件;(不变性条件本质上就是确定状态变量自身的约束条件和状态变量间的依赖关系)

对象状态变量的不变性条件与后验条件约束了在对象状态上有哪些状态和状态转换是有效的,也就是对象状态变量的值哪些是有效的,哪些状态之间的转换时有效的,而哪些状态变量值和哪些状态间的转换时无效的。

3)建立对象状态的并发访问管理策略

同步策略:定义了如何在不违背不破坏对象不可变性或后验性的情况下对其状态的访问操作进行协同,规定了如何将不可变性、线程封闭、加锁机制等结合起来已维护线程的安全性,并且还规定了哪些变量由哪些锁来保护。

(2)构建线程安全类的过程

1)收集同步需求

确定构成对象状态的所有变量和对象状态变量不可变性条件的过程。

2)依赖状态的操作

在依赖对象状态的操作上(比如先验条件)如何设计,最简单的办法是通过现有库中的类来实现依赖状态的行为。

3)状态的所有权

确定状态变量如何共享和发布

2、构建线程安全类的三种方法:

(1)构建线程安全类的最简单方式:实例封闭

将数据封装在对象的内部,可以将数据的访问限制在对象的方法上,从而更容易确保线程在访问数据时总能持有正确的锁。

封闭机制和加锁机制结合起来,就可以确保以线程安全的方式使用非线程安全的对象

Java监视器模式:封装对象的所有可变状态,并有对象自己的内置锁来保护。

(2)组合多个类构建线程安全类(线程安全性的委托)

1)单个状态变量情况下

将单个状态变量委托给线程安全的类(如ConcurrentHashMap等)

2)多个状态变量且没有不可变性的约束下

每个状态变量都交给一个线程安全类维护

3)多个状态变量且存在不可变性的约束

委托和加锁机制联合起来才能实现在构建线程安全类的过程中不破坏多个状态变量不可变性条件。

4)发布底层的状态变量

如果一个类由多个独立且线程安全的状态变量组成,并且在所有的操作中都不含无效的状态转换,那么可以将线程安全性委托给底层的状态变量。

底层状态变量的发布:如果一个状态变量是线程安全的类,并且没有任何不变性条件来约束它的值,在变量的操作上也不存在任何不允许的状态转换,那么就可以安全的发布这个变量。

(3)在现有线程安全类中添加功能以构建新的线程安全类

1)修改现有线程安全类代码,新增功能

2)扩展现有线程安全类

3)使用辅助类扩展类的功能

4)组合

3、线程安全类的维护

将同步策略文档化

4.构建线程安全性委托的基础构建模块

(1)同步容器类

同步容器只有所有对容器状态的访问操作都串行化,才能实现他们的线程安全性。在并发的环境中,访问容器的状态在客户端没有加锁的情况下不是线程安全的。

实现线程安全的方式:封装容器的状态,把所有公有的的方法都进行同步,使得每次只有一个线程可以访问容器的状态。

缺点:严重降低并发性,吞吐量低

(2)并发容器

(1)ConCurrentHashMap

(2)CopyOnWriteArrayList

(3)阻塞队列和生产者-消费者模式

(1)BlockingQueue 阻塞队列:适用于生产者-消费者模式(消费者共享一个工作队列)

(2)BlockingDeque 阻塞双端队列:适用于工作密取模式(每个消费者都有一个自己的双端队列,当自己的双端队列完成后消费者可以从其他消费者的双端队列内获取)

工作密取模式比生产者-消费者模式更具可伸缩性,因为工作密取的每个消费者都有自己的工作队列,就减少了在因共享队列上因获取的数据而发生的竞争。

(4)阻塞方法和中断方法

(5)同步工具类

(1)CountDownLatch

(2)FutureTask

(3)Semaphore

(4)CyclicBarrier和Exchanger

(6)构建高效且可伸缩的结果缓存

那些年读过的书《Java并发编程实战》二、如何设计线程安全类的更多相关文章

  1. 《Java并发编程实战》学习笔记 线程安全、共享对象和组合对象

    Java Concurrency in Practice,一本完美的Java并发参考手册. 查看豆瓣读书 推荐:InfoQ迷你书<Java并发编程的艺术> 第一章 介绍 线程的优势:充分利 ...

  2. 读书笔记-----Java并发编程实战(一)线程安全性

    线程安全类:在线程安全类中封装了必要的同步机制,客户端无须进一步采取同步措施 示例:一个无状态的Servlet @ThreadSafe public class StatelessFactorizer ...

  3. 《Java并发编程实战》第二章 线程安全性 读书笔记

    一.什么是线程安全性 编写线程安全的代码 核心在于要对状态訪问操作进行管理. 共享,可变的状态的訪问 - 前者表示多个线程訪问, 后者声明周期内发生改变. 线程安全性 核心概念是正确性.某个类的行为与 ...

  4. 《Java并发编程实战》第二章 线程安全 札记

    一个.什么是线程安全 编写线程安全的代码 其核心是管理国事访问的操作. 共享,可变的状态的訪问 - 前者表示多个线程訪问, 后者声明周期内发生改变. 线程安全性 核心概念是正确性.某个类的行为与其规范 ...

  5. java并发编程实战:第二章----线程安全性

    一个对象是否需要是线程安全的取决于它是否被多个线程访问. 当多个线程访问同一个可变状态量时如果没有使用正确的同步规则,就有可能出错.解决办法: 不在线程之间共享该变量 将状态变量修改为不可变的 在访问 ...

  6. Java并发编程实战 第8章 线程池的使用

    合理的控制线程池的大小: 下面内容来自网络.不过跟作者说的一致.不想自己敲了.留个记录. 要想合理的配置线程池的大小,首先得分析任务的特性,可以从以下几个角度分析: 任务的性质:CPU密集型任务.IO ...

  7. Java并发编程实战(5)- 线程生命周期

    在这篇文章中,我们来聊一下线程的生命周期. 目录 概述 操作系统中的线程生命周期 Java中的线程生命周期 Java线程状态转换 运行状态和阻塞状态之间的转换 运行状态和无时限等待状态的切换 运行状态 ...

  8. Java 并发编程(三)为线程安全类中加入新的原子操作

    Java 类库中包括很多实用的"基础模块"类.通常,我们应该优先选择重用这些现有的类而不是创建新的类.:重用能减少开发工作量.开发风险(由于现有类都已经通过測试)以及维护成本.有时 ...

  9. 《Java并发编程实战》第八章 线程池的使用 读书笔记

    一.在任务与运行策略之间的隐性解耦 有些类型的任务须要明白地指定运行策略,包含: . 依赖性任务.依赖关系对运行策略造成约束.须要注意活跃性问题. 要求线程池足够大,确保任务都能放入. . 使用线程封 ...

  10. Java并发编程(十)设计线程安全的类

    待续... 线程安全的类 之前学了很多线程安全的知识,现在导致了我每次用一个类或者做一个操作我就会去想是不是线程安全的.如果每次都这样的考虑的话就很蛋疼了,这里的思路是,将现有的线程安全组件组合为更大 ...

随机推荐

  1. Django 源码小剖: Django 中的 WSGI

    Django 其内部已经自带了一个方便本地测试的小服务器, 所以在刚开始学习 Django 的时候并不需搭建 apache 或者 nginx 服务器. Django 自带的服务器基于 python w ...

  2. centos7安装elasticsearch-head

    elasticsearch-head安装前准备 1.操作系统64位CentOS Linux release 7.2.1511 (Core)2.git是必需的elasticsearch-head是一款开 ...

  3. java 注解默认值

    package com.zejian.annotationdemo; import java.lang.annotation.ElementType; import java.lang.annotat ...

  4. Fedora 21 安装 Bumblebee with the NVIDIA proprietary drivers

    最新文章:Virson's Blog 参考Fedora Wiki:http://fedoraproject.org/wiki/Bumblebee#Fedora_21

  5. 树莓派集群实践——nfs

    1.安装 apt-get install nfs-common nfs-kernel-server 省略(sudo apt-get install portmap  --->install rp ...

  6. jQuery表格列宽可变,兼容firfox

    本demo使用jQuery包,实现表格列宽可拖拽功能,并实现页面reset时的重新布局.使用jQuery,方便函数的调用,给要处理的表格添加id 后,直接调用$("#id").mo ...

  7. Git合并最近的commit

    合并commit的做法一般用在pull request的时候,把开发同一功能时的所有琐碎的commit合并到一个(假装自己的代码是高质量代码(手动滑稽)).主要使用的命令是git rebase 或者g ...

  8. 如何将Unicode文本写到日志文件中

    有时为了定位问题,我们需要结合打印日志来处理.特别是较难复现的,一般都需要查看上下文日志才能找出可能存在的问题.考虑到程序要在不同语言的操作系统上运行,程序界面显示要支持Unicode,打印出来的日志 ...

  9. angular 4 和django 1.11.1 前后端交互 总结

    首先 angular4 和django 1.11.1交互 有跨域问题 所以先关闭cors 和csrf验证 一.解决跨域问题 cors github django-cors-headers 1)安装co ...

  10. NHibernate.3.0.Cookbook第一章第五节Setting up a base entity class

    Setting up a base entity class设置一个实体类的基类 在这节中,我将给你展示怎么样去为我们的实体类设置一个通用的基类. 准备工作 完成前面三节的任务 如何去做 1.在Ent ...