上一篇讨论了如何解决线程安全的问题,今天总结如何设计一个线程安全的类;

创建线程安全类的关注点

一个类要想线程安全,除了上一篇文章通过外部解决方式外,还可以通过合理的设计类的内部来解决,使类本身就线程安全,那么要怎么才能使类是线程安全的呢?

类不是线程安全的原因主要就是它包含了一些属性,这些属性是这个类实例对象的变量,这些变量影响着对象状态,由于对这些属性的访问在多线程情况下出现一些不安全使得对象状态并不符合预期导致类的不安全,所以设计线程安全类大概方向就是保证这些影响对象状态的变量,在Java并发编程实战中的总结如下:

找出构成对象状态的所有变量;

找出约束状态变量的不变性条件;

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

这里先解释下不变性条件,在一些类的它的一些变量的变化是有一定规则的,比如类中定义一个属性表示苹果卖出了多少斤,卖出就增加,退货就减少,但是它肯定不会是一个负值,不为负值这就是这个变量的不变性条件。在比如类中定义了最大值与最小值,那么在这两个变量只有有一个不变性条件就是最大值要大于等于最小值。

简单解释了不变性条件再来理解下上面3条:可以把这3条分成3个步骤,首先是找出构成对象状态的所有变量,第二步是找出变量的约束条件,最后是上面两步找出的变量进行并发访问控制保证不变性条件的约束,对比较独立的属性直接进行并发访问,但是对有关联的那就必须要更多的机制保证这个约束

所以我们可以把设计线程安全的类步骤分成以下三块:

1、找出所有需要同步的属性,保证不可变条件和后验条件(方法执行后必须为真的条件),比如上面举的卖出苹果的重量,比如最大值与最小值关系;

2、保证一些依赖一些状态的操作正确执行(先验条件方法执行前必须为真的条件),比如单例模式中实体为null的时候才初始化;

3、一定要控制这些属性的所有权,基础类型的属性可能比较好控制,有些是引用类型但又要保证线程安全的,那就要严格控制所有权,否则有可能其他线程拿到这个引用进行修改这个对象的内容,造成线程不安全;

已有对象如何保证线程安全

我们可以设计出线程安全的类,但是有可能有些对象已经存在,然后它并不是线程安全,现在却需要保证它的线程安全,那该如何做呢?

通过监视器模式实现,把对象封装到一个新对象里面,所有对这个对象的访问都通过新对象的方法访问,然后保证新对象的方法是线程安全的就行了。

并不一定需要自己实现线程安全

但是有时候我们并不是一定要设计成线程安全的类,如果已经存在一些线程安全的类可以保证我们需要的线程安全,还是要尽量用现有的,比如上面提到过苹果卖出的重量,就可以利用AtomicInteger来保证安全,再比如一些缓存也可以用ConcurrentMap来保证线程安全,把我们需要保证的线程安全委托给一些线程安全的类。

但是委托并不是一定有用的,比如前面的最大、最小值例子,如果定义成现AtomicInteger也无法保证它们的不可变条件的约束!这种可能就只能加锁了,但是如果他们两个并没有不可变条件约束是两个无关的共享变量,还是可以把多个无关的状态变量委托给线程安全的类

如何扩展线程安全类

那么如果一个线程安全的类功能不满足我们的需求,需要扩展一些功能,可是又不能修改这个类,那么就必须要对这个类进行扩展,扩展分两种方法继承、客户端扩展。继承实现比较简单,继承的类只要在保证新增的方法是线程安全的,那么它整个都是线程安全的,不过客户端扩展可能情况复杂一点,一个错误的例子如下图:

新增的方法虽然加了锁,可是它是加在ListExpand这个类的对象上,而list方法里面的锁则是在list这个对象上,所有整体并不是线程安全的。是应该在方法内部然后锁list这个对象!

还可以把一些线程不安全的类通过继承然后重写方法实现线程安全,不过这和前面提到的通过监视器模式实现比较相似。

总结

从如何实现线程安全的类到线程不安全类如何保证线程安全,然后是如何利用已有线程安全类实现线程安全,当线程安全类不满足需求时又该如何扩展,这四个方面都进行了梳理。

Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!

线程安全list_多线程开发之如何创建一个线程安全的类相关推荐

  1. 多线程(一):认识和创建一个线程

    认识和创建一个线程 一.进程与线程 1.进程 (1).什么是进程 (2).创建进程 2.线程 3.进程和线程的关系 4.为什么要使用多线程 二.创建一个线程 1.创建线程的方式 (1).继承Threa ...

  2. C#多线程学习(二) 如何操纵一个线程

    C#多线程学习(二) 如何操纵一个线程 原文链接:http://kb.cnblogs.com/page/42529/ [1] C#多线程学习(二) 如何操纵一个线程 [2] C#多线程学习(二) 如何 ...

  3. java里新建线程设置线程名字_多线程开发不得不掌握,设置和获取线程名称及JVM如何运行的...

    原标题:多线程开发不得不掌握,设置和获取线程名称及JVM如何运行的 欲善编程,多看.多敲.多讨论:动眼.动手.动大脑. 1 如何设置和获取线程名称 多线程的运行状态是不确定的,在程序开发过程中,想要获 ...

  4. 【C/C++多线程编程之三】创建pthread线程

    多线程编程之创建pthread线程 Pthread是 POSIX threads 的简称,是POSIX的线程标准.           创建线程是多线程编程的第一步,理解线程创建时多线程编程的关键. ...

  5. PySide2多线程问题示例:创建新线程、子线程发射信号到主界面

    PySide2多线程问题示例:创建新线程.子线程发射信号到主界面 本文是在pyside学习过程中的记录,从无子线程.子线程在主程序中直接操作Qt界面.子线程发射信号操作主界面三个步骤出发,记录对多线程 ...

  6. 多线程系列教材 (一)- Java 创建一个线程的三种方式

    多线程即在同一时间,可以做多件事情. 创建多线程有3种方式,分别是继承线程类,实现Runnable接口,匿名类 步骤1:线程概念 步骤2:创建多线程-继承线程类 步骤3:创建多线程-实现Runnabl ...

  7. java多线程为啥一直用的一个线程_一个Java多线程的问题,颠覆了我多年的认知!...

    作者 | ithuangqing 来源 | 编码之外(ID:ithuangqing) 碰见个奇怪的多线程问题 小白们也不用怕,今天的文章你们都能看得懂,最近的学习中,碰到这样的一个问题: Java创建 ...

  8. 使用Thread类和Runnable方法来创建一个线程的区别

    第一:Thread类需要被继承,然后重写run()方法,但是Java中的类是单继承的,也就是说,若某个类继承Thread获取线程功能后,就不能再继承别的类了.但是Runnable接口解决了这个问题,某 ...

  9. Java 创建一个线程的三种方式

    Java 创建一个线程的三种方式 更多内容,点击了解: https://how2j.cn/k/thread/thread-start/353.html 创建多线程有3种方式,分别是继承线程类,实现Ru ...

最新文章

  1. Python编程基础:第三十九节 面向对象编程Object Oriented Programming
  2. 协同OA对业务和管理进行流程的梳理
  3. Java是解释型还是编译型?
  4. linux chrome 管理员,Linux下google chrome浏览器flash无法启用的解决
  5. wordpress archive.php,wordpress分类目录模板(archive.php)制作
  6. 第 3-4 课:数据结构——队列详解 + 面试题
  7. Android 自己定义View (二) 进阶
  8. html5 canvas签字,HTML5 canvas实现电子签名
  9. XBOX Series X规格如此强悍,如果被破解安装了win10,将对PC行业带来什么影响?
  10. Numpy学习笔记(三)
  11. c语言编写面条排序算法,腾讯PCG事业部腾讯视频面经
  12. Linux关机、开机、重启、定时重启、定时关机详细命令(shutdown命令)
  13. 第08课:GDB 实用调试技巧( 上)
  14. 苹果系统被曝漏洞, 大麦网再遭撞库攻击 | 宅客周刊
  15. 计算格拉姆矩阵_如何用简单易懂的例子解释格拉姆矩阵/Gram matrix?
  16. EFS加密解密----重装系统后
  17. 电容笔和Apple pencil的区别?适合ipad画画的电容笔推荐
  18. 计算机台式硬件排名,CPU天梯图2019年1月最新版 一月台式电脑处理器排名
  19. 个人腾讯云服务器的搭建
  20. [宝塔版] 如何搭建一个微信小程序开源商城?

热门文章

  1. vue如何在手机上查看vue-cli构建的项目
  2. webpack的sourcemap
  3. 送给那些有代码基础但仍旧不会学自动化测试的朋友们
  4. web.xml文件中mime-mapping
  5. vi/vim: 文件浏览和缓冲区浏览
  6. 用eclipse开发flex程序--- 配置eclipse(flex builder 3.0)
  7. 作为测试人员,这些工具不会真不行
  8. CSS基础——CSS样式的引入和规则【学习笔记】
  9. 剑指offer面试题[30]-最小的k个数
  10. 王学丹 确定测试原始需求