目录

  • 一、为什么这种方式不能实现线程安全性?
  • 二、组合
  • 三、同步容器类
  • 四、隐藏迭代器
  • 五、并发容器
  • 六、ConcurrentHashMap
  • 七、享誉全球的 Java 经典著作《Java核心技术》基于Java 17全面升级!
  • 八、Java核心技术大会2022

一、为什么这种方式不能实现线程安全性?

分析一段代码:

package com.guor.util;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class ListHelper<E> {public List<E> list = Collections.synchronizedList(new ArrayList<E>());public synchronized boolean putIfAbsent(E x){boolean absent = !list.contains(x);if(absent){list.add(x);}return absent;}
}

毕竟putIfAbsent已经声明了synchronized 类型的变量,对不对?问题在于在错误的锁上进行了同步。无论list使用哪一个锁来保护它的状态,可以确定的是,这个锁并不是ListHelper上的锁。ListHelper只是带来了同步的假象,尽管所有的链表操作都被声明为synchronized,但却使用了不同的锁,这意味着putIfAbsent相对于List的其它操作来说并不是原子的,因此就无法确保当putIfAbsent执行时另一个线程不会修改链表。
要想使这个方法能正确执行,必须使List在实现客户端加锁或外部加锁时使用同一个锁。客户端加锁是指,对于使用某个对象X的客户端代码,使用X本身用于保护器状态的锁来保护这段客户端代码。要使用客户端加锁,你必须知道对象X使用的是哪一个锁。
在Vector和同步封装器的文档中指出,它们通过使用Vector或封装器的内置锁来支持客户端加锁,下面代码可以实现线程安全的list操作。

public boolean putIfAbent(E x){synchronized (list){boolean absent = !list.contains(x);if(absent){list.add(x);}return absent;}
}

二、组合

当为现有的类添加一个原子操作时,有一种更好的方法:组合。
下面代码中ImprovedList通过将List对象的操作委托给底层的List实例来实现List的操作,同时还添加了一个原子的putIfAbsent方法。(与Collections.synchronizedList和其它容器封装器一样,ImprovedList假设把某个链表对象传给构造函数以后,客户代码不会再直接使用这个对象,而只能通过ImprovedList来访问它。)

package com.guor.util;import java.util.List;public class ImprovedList<T> implements List<T> {private final List<T> list;public ImprovedList(List<T> list){this.list = list;}public synchronized boolean putIfAbsent(T x){boolean absent = !list.contains(x);if(absent){list.add(x);}return absent;}public synchronized void clear(){list.clear();}...
}

ImprovedList通过自身的内置锁增加了一层额外的加锁,它并不关心底层的list是否是线程安全的,即使List不是线程安全的或者修改了它的加锁实现,ImprovedList也会提供一致的加锁机制来实现线程安全性。虽然额外的同步层可能导致轻微的性能损失,但与模拟另一个对象的加锁策略相比,ImprovedList更为健壮。事实上,我们使用了Java监视器模式来封装现有的List,并且只要在类中拥有指向底层List的唯一外部引用,就能确保线程安全性。

三、同步容器类

同步容器类包括Vector和Hashtable,这些实现线程安全的方式是:将它们的状态封装起来,并对每个公有方法都进行同步,使得每次只有一个线程能访问容器的状态。
同步容器类都是线程安全的,但在某些情况下可能需要额外的客户端加锁来保护符合操作。容器上常见的复合操作包括:迭代、跳转以及条件运算,例如“若没有则添加”。在同步容器类中,这些符合操作在没有客户端加锁的情况下仍然是线程安全的,但当其他线程并发地修改容器时,它们可能会表现出意料之外的行为。

四、隐藏迭代器

虽然加锁可以防止迭代器抛出ConcurrentModificationException,但你必须要记住所有对共享容器进行迭代的地方都需要加锁。实际情况要更加复杂,因为在某些情况下,迭代器会隐藏起来。比如log.info("set content is :"+set),编译器将字符串的连接操作转换为调用StringBuilder.append(Object),而这个方法又会调用容器的toString方法,标准容器的toString方法将迭代容器,并在每个元素上调用toString来生成容器内容的格式化表示。
容器的hashCode和equals等方法也会间接地执行迭代操作,当容器作为另一个容器的元素和键值时,就会出现这种情况。

五、并发容器

jdk1.5提供了多种并发容器来改进同步容器的性能。同步容器将所有对容器状态的访问都串行化,以实现它们的线程安全性。这种方法的代价是严重降低并发性,当多个线程竞争容器的锁时,吞吐量将严重降低。
另一方面,并发容器是针对多个线程并发访问设计的。在jdk1.5中增加了ConcurrentHashMap,用来替代同步且基于散列的Map以及CopyOnWriteArrayList,用于在遍历操作为主要操作的情况下代替同步的List。在新的ConcurrentMap接口中增加了对一些常见复合操作的支持,例如“若没有则添加”、替换以及有条件删除等。
通过并发容器来代替同步容器,可以极大地提高伸缩性并降低风险。
jdk1.5增加了两种新的容器类型:Queue和BlockingQueue。Queue用来临时保存一组等待处理的元素。它提供了几种实现,包括ConcurrentLinkedQueue,这是一个传统的先进先出队列,以及PriorityQueue,这是一个非并发的优先队列。Queue上的操作不会阻塞,如果队列为空,那么获取元素的操作将返回空值。虽然可以用List来模拟Queue的行为,事实上,正是通过LinkedList来实现Queue的,但还需要一个Queue的类,因为它能去掉List的随机访问需求,从而实现更高效的并发。
BlockingQueue扩展了Queue,增加了可阻塞的插入和获取等操作,如果队列为空,那么获取元素的操作将一直阻塞,直到队列中出现一个可用的元素。如果队列已满,那么插入元素的操作将一直阻塞,直到队列中出现可用的空间。
同步容器在执行每个操作期间都持有一个锁。

六、ConcurrentHashMap

与HashMap一样,ConcurrentHashMap也是一个基于散列的Map,但它使用了一种完全不同的加锁策略来提供更高的并发性和伸缩性。ConcurrentHashMap并不是将每个方法都在同一个锁上同步并使得每次只能有一个线程访问容器,而是使用一种更细的加锁机制来实现更大程度的共享,这种机制成为分段锁。在这种机制中,任意数量的读取线程可以并发地访问Map,执行读取操作的线程和执行写入操作的线程可以并发地访问Map,并且一定数量的写入线程可以并发地修改Map。ConcurrentHashMap带来的结果是,在并发访问环境下将实现更高的吞吐量,而在单线程环境中只损失非常小的性能。
ConcurrentHashMap返回的迭代器具有弱一致性,而并非“及时失败”。弱一致性的迭代器可以容忍并发的修改,当创建迭代器时会遍历已有的元素,并可以在迭代器被构造后将修改操作反映给容器。

七、享誉全球的 Java 经典著作《Java核心技术》基于Java 17全面升级!

Java 诞生 27 年来,这本享誉全球的 Java 经典著作《Core Java》一路伴随着 Java 的成长,得到了百万 Java 开发者的青睐,几乎出现在每个“学Java要看什么书”类似的书单里,影响了几代技术人。

27年间,每当 Java 有新的 LTR 版本发布,这本书都会随之更新,这次也不例外。现在,针对 Java 17 新特性的《Java核心技术》第 12 版*中文版(卷1)终于上市了!

《Java核心技术》第 12 版涵盖了 Java 17 的最新特性,相应调整了部分内容结构,同时延续之前版本的优良传统,利用清晰明了的示例加以解释,并提供了全部示例代码,以便读者学习和灵活应用。它将续写从前的辉煌,使开发者能及时跟上 Java 前进的步伐。


我们寻找了50位曾经看着《Java核心技术》这本书成长起来的KOL推荐本书!大家的寄语全部收录在第12版新书中!
这本书究竟是怎样的一本书,得到众多开发者的一致推荐呢?
1、《Java核心技术》并非市面那些零基础速成的书,很好地避免了开发基础书容易犯的“大而泛”的问题,尽管内容繁多,但对知识点的介绍并非泛泛而过。通过周密组织,从Java繁杂的内容中整理出一条清晰的主线,构成一个完整的知识体系。
2、整本书不仅让你深入了解设计和实现Java应用涉及的所有基础知识和Java特性,还会帮助你掌握开发Java程序所需的全部基本技能。
3、作者凯.霍斯特曼是Java技术坚定的倡导者,至今仍常年在国际上的各类计算机峰会上进行技术分享。在位于硅谷中心的圣何塞州立大学教学30余年,为硅谷的顶尖科技公司培养了大量计算机专业人才。非常熟知大厂要什么!所以他的书也是非常有针对性。
4、为帮助大家更轻松地学习Java,作者还亲自录制了配套视频讲解课程,视频配有中文配音+中文字幕,与纸书涵盖内容基本一致,适配Java SE8以后的版本。
纸书+视频搭配学习,学习Java更轻松。(B站搜索“Java核心技术站”直达)。

相信在学习Java的道路上有了《Java核心技术》这本书的辅助,你一定可以做到事半功倍。

八、Java核心技术大会2022

视频号【华章计算机】免费观看所有直播,8个专场、24个主题、近30位国内外顶级专家深度分享与探讨Java的变革与未来。

上一篇:【Java 多线程 7】通过socket、多线程、动态代理、反射 实现RPC远程方法调用

下一篇:Java学习路线总结,搬砖工逆袭Java架构师

【Java 多线程 8】同步容器与并发容器相关推荐

  1. java双端队列工作密取,同步器皿、并发容器、阻塞队列、双端队列与工作密取...

    同步容器.并发容器.阻塞队列.双端队列与工作密取 在多线程的开发中经常会碰到数据的并发修改,并发存取,因此正确的使用不同的容器很关键,直接影响到数据的正确性.下面主要记录下三种重要的队列,以及一种非常 ...

  2. Java多线程精讲(非高并发-授课专用)附synchronized

    Java多线程精讲(非高并发-授课专用) 目录 程序,进程,线程的基本概念 start与run的区别 函数测试demo: 创建线程(一)[new Thread()] 创建线程(二)[extends T ...

  3. java实验多线程机制_使用Java多线程的同步机制编写应用程序 PDF 下载

    使用Java多线程的同步机制编写应用程序 PDF 下载 本站整理下载: 相关截图: 主要内容: 一. 实验名称 使用Java多线程的同步机制编写应用程序 二. 实验目的及要求 1.理解并行/并发的概念 ...

  4. Java多线程概念[同步容器,并发容器](二)

    同步容器 同步容器通过synchronized关键字修饰容器,保证同一时刻只有一个线程使用容器,从而使容器线程安全. synchronized的意思的同步. 1.Vector和ArrayList都实现 ...

  5. Java并发(9)- 从同步容器到并发容器

    引言 容器是Java基础类库中使用频率最高的一部分,Java集合包中提供了大量的容器类来帮组我们简化开发,我前面的文章中对Java集合包中的关键容器进行过一个系列的分析,但这些集合类都是非线程安全的, ...

  6. 同步容器和并发容器的区别

    同步容器:可以简单地理解为通过synchronized来实现同步的容器,如果有多个线程调用同步容器的方法,它们将会串行执行.比如Vector,Hashtable,以及Collections.synch ...

  7. java多线程 门闩_Java线程与并发编程实践----同步器(倒计时门闩,同步屏障)...

    Java提供的synchronized关键字对临界区进行线程同步访问.由于基于synchronized很难 正确编写同步代码,并发工具类提供了高级的同步器.倒计时门闩(countdown latch) ...

  8. Java多线程的同步优化的6种方案

    概述 处理器上的寄存器的读写的速度比内存快几个数量级,为了解决这种速度矛盾,在它们之间加入了高速缓存. 加入高速缓存带来了一个新的问题:缓存一致性.如果多个缓存共享同一块主内存区域,那么多个缓存的数据 ...

  9. Java多线程的同步机制(synchronized)

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ...

  10. java多线程、同步、异步

    1.多线程.并发.异步.并行: 多线程是对cpu剩余劳动力的压榨,是一种技术.想想web server 需要处理大量并发请求的场景,是你同时给A,B,C...打电话(你的思维在不断切换,如一边给女朋友 ...

最新文章

  1. 每次有人来家里,总有人问我这个积木在哪买的
  2. 领域驱动设计-基本概念
  3. 计算机系统及原理pdf,计算机系统及工作原理教学设计.pdf
  4. NLTK was unable to find the megam file!
  5. 小马哥----山寨高仿小米5 图片1:1机型 机型曝光 与真假鉴别方法
  6. web前端开发基础入门教程之HTML5 浏览器支持
  7. android开发者模式 device,Settings中开发者模式的影藏和显示
  8. 个人sublime定制
  9. 台式计算机关机后自行重启,台式电脑关机后自动重启怎么办?台式电脑关机后自动开机的处理办法...
  10. 4 个方法养成大神级 “反内耗“ 体质
  11. VC中CTime和SYSTEMTIME转化
  12. HTML5利用canvas画布绘制哆啦A梦
  13. ESP32使用freeRTOS的消息队列
  14. java全栈系列之JavaSE-稀释数组029
  15. HackTheBox-baby interdimensional internet
  16. SEO优化 - 使用nginx301重定向顶级域名到www二级域名
  17. 计算机键盘无线遥控器实现方法,利用红外遥控器实现单片机键盘无线式操作
  18. 黄聪:Windows7立体声混音设置方法(stereo mix)(转)
  19. python共轭复数_python print出共轭复数的方法详解
  20. 用python画柯南

热门文章

  1. 内连接和外连接的区别--举例
  2. win8 oracle 卸载,大神细说win8系统卸载oracle的法子
  3. WIN7中文专业版安装英文语言包的方法
  4. 网站压测工具Apache-ab,webbench,Apache-Jemeter
  5. Problem A Codeforces 20C 最短路(dj,spfa)
  6. java 添加字段注释_java自定义注释
  7. html做出文字凹凸效果,css3怎么实现字体凹陷凸出效果?(附代码)
  8. 2022-07-08 Unity Json2——LitJson
  9. Unity 使用LitJson 解析Json数据
  10. 水经注叠加cad_水经注CAD智能影像加载插件使用教程