个人博客网:https://wushaopei.github.io/    (你想要这里多有)

一、死锁

1、死锁的定义

所谓的死锁是指两个或两个以上的线程在等待执行的过程中,因为竞争资源而造成的一种互相等待的现象。若不受外力作用,他们都将无法推进下去。此时,处于系统中所处的状态就是死锁。

2、发生死锁所必须具备的条件:

互斥条件:它是指进程对所分配的资源进行排他性的使用,在一定时间内,某资源只由一个进程在用,如果此时还有其他进程请求资源,请求者只能等待。直到占有资源的进程用完或释放之后才可以继续使用。

请求和保持条件:它是指进程已经保持了至少一个资源,又提出了新的资源请求,该资源已被其它进程占用。此时,请求进程阻塞,对自己或者其它资源保持不放;

不剥夺条件:指进程获取资源在用完之前不能被剥夺,只能在使用完后再由自己释放;

环路等待条件:发生死锁的时候,一定存在一个进程的资源是一个环形的链。

3、代码演示死锁:

  1. /**
  2. * 一个简单的死锁类
  3. * 当DeadLock类的对象flag==1时(td1),先锁定o1,睡眠500毫秒
  4. * 而td1在睡眠的时候另一个flag==0的对象(td2)线程启动,先锁定o2,睡眠500毫秒
  5. * td1睡眠结束后需要锁定o2才能继续执行,而此时o2已被td2锁定;
  6. * td2睡眠结束后需要锁定o1才能继续执行,而此时o1已被td1锁定;
  7. * td1、td2相互等待,都需要得到对方锁定的资源才能继续执行,从而死锁。
  8. */
  9. @Slf4j
  10. public class DeadLock implements Runnable {
  11. public int flag = 1;
  12. //静态对象是类的所有对象共享的
  13. private static Object o1 = new Object(), o2 = new Object();
  14. @Override
  15. public void run() {
  16. log.info("flag:{}", flag);
  17. if (flag == 1) {
  18. synchronized (o1) {
  19. try {
  20. Thread.sleep(500);
  21. } catch (Exception e) {
  22. e.printStackTrace();
  23. }
  24. synchronized (o2) {
  25. log.info("1");
  26. }
  27. }
  28. }
  29. if (flag == 0) {
  30. synchronized (o2) {
  31. try {
  32. Thread.sleep(500);
  33. } catch (Exception e) {
  34. e.printStackTrace();
  35. }
  36. synchronized (o1) {
  37. log.info("0");
  38. }
  39. }
  40. }
  41. }
  42. public static void main(String[] args) {
  43. DeadLock td1 = new DeadLock();
  44. DeadLock td2 = new DeadLock();
  45. td1.flag = 1;
  46. td2.flag = 0;
  47. //td1,td2都处于可执行状态,但JVM线程调度先执行哪个线程是不确定的。
  48. //td2的run()可能在td1的run()之前运行
  49. new Thread(td1).start();
  50. new Thread(td2).start();
  51. }
  52. }

执行并打印结果:

  1. 21:13:12.979 [Thread-1] INFO com.mmall.concurrency.example.deadLock.DeadLock - flag:0
  2. 21:13:12.979 [Thread-0] INFO com.mmall.concurrency.example.deadLock.DeadLock - flag:1
  3. Process finished with exit code 1

相关扩展:Java项目中使用log记录日志的一些总结

二、多线程并发最佳实践

1、使用本地变量:应该使用本地变量,而不是创建一个类或实例变量。通常情况下,开发人员使用对象实例作为一个类,可以节省内存,并可以重用。因为每次在方法中创建新的本地变量会消耗很多内存。

2、使用不可变类:如 String 、Integer等,一旦创建就不会改变了,不可变类可以降低代码中的同步数量

3、最小化锁的作用域范围: S=1/(1-a+a/n)

4、使用线程池的Executor,而不是直接new Thread执行:

创建一个线程的代价是昂贵的,如果你要得到一个可伸缩的java应用,那么你需要使用线程池,从线程池来管理线程,jdk中提供了各种方法实现

5、宁可使用同步也不要使用线程的wait和notify

从java1.5以后增加了许多的同步工具,要优先使用同步工具,而不是使用wait和notify方法

6、使用BlockingQueue实现生产-消费模式

7、使用并发集合而不是加了锁的同步集合

8、使用Semaphore创建有界的访问

9、宁可使用同步代码块,也不使用同步的方法

10、避免使用静态变量

三、Spring与线程安全

Spring bean  : singleton 、 prototype

无状态对象

无状态对象:就是自身没有状态的对象,当然也就不会因为多个线程交替调度破坏自身的状态而导致安全问题。无状态对象包括经常使用的DTO、VO,只作为数据实体的模型对象。

四、HashMap与ConcurrentHashMap解析

1、HashMap 的数据结构:

在java编程语言中,最基本的结构有两种,一个是数组,另外一个就是指针,即引用。

HashMap的底层就是一个数组结构,数组的每一项又是一个链表,当我们新建HashMap的时候就会初始化一个数组出来。

HashMap有两个参数影响它的性能,分别是初始容量加载因子。

由源码可知,HashMap的初始容量为16,

由上图中,可知HashMap的默认加载因子为0.75.

当HashMap 的长度达到的容量长度满足初始值的0.75时,就会调用resize()方法进行扩容:

我们也可以根据需要指定HashMap的初始化容量和加载因子。

2、HashMap 的线程安全性:

HashMap线程不安全的,主要体现在前面的resize()方法,它可能会导致死循环的发生,并且在使用迭代器的时候fasfree。当HashMap的长度超过了它的capacity * loadFactor时,就需要对它进行扩容,具体方法是:它要创建一个新的长度为原来容量的两倍的数组。它保证新的容量为2的N次方,从而保证寻址的方式依然适用。同时,它原来的数组会全部插入到新的数组中。这个过程我们称之为rehash。

这个方法并不保证线程安全,而且在多线程并发调用时可能陷入死循环。

3、HashMapd的ReHash 操作示意图:

单线程下的ReHash操作:

多线程下的ReHash操作:

4、ConcurrentHashMap的底层数据结构:

5、ConcurrentHashMap和HashMap的不同点:

  • ConcurrentHashMap是线程安全的,HashMap是线程不安全的;
  • HashMap允许key\value为空,而ConcurrentHashMap是不允许的

6、ConcurrentHashMap 改进后

Java7以后针对并发访问引入了Segment这个结构,实现了分段锁,提高并发度,与Segment的个数是相等的。Java8以后为了进一步提高并发性,它废弃了这里面的分段锁方案,并且直接使用一个大的数组,同时为了提高hash碰撞下的寻址做了性能优化。

Java8以后它的链表的长度超过一定的值(默认为8),这里的链表就会变成了红黑树。

Java并发编程 (十) 多线程并发拓展的更多相关文章

  1. java并发编程--第一章并发编程的挑战

    一.java并发编程的挑战 并发编程需要注意的问题: 并发编程的目的是让程序运行的更快,然而并不是启动更多的线程就能让程序最大限度的并发执行.若希望通过多线程并发让程序执行的更快,会受到如下问题的挑战 ...

  2. java并发编程与高并发解决方案

    下面是我对java并发编程与高并发解决方案的学习总结: 1.并发编程的基础 2.线程安全—可见性和有序性 3.线程安全—原子性 4.安全发布对象—单例模式 5.不可变对象 6.线程封闭 7.线程不安全 ...

  3. Java并发编程系列-(1) 并发编程基础

    1.并发编程基础 1.1 基本概念 CPU核心与线程数关系 Java中通过多线程的手段来实现并发,对于单处理器机器上来讲,宏观上的多线程并行执行是通过CPU的调度来实现的,微观上CPU在某个时刻只会运 ...

  4. Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁

    Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线程join.守护线程.线程互斥锁 目录 Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线 ...

  5. 并发编程概述--C#并发编程经典实例

    优秀软件的一个关键特征就是具有并发性.过去的几十年,我们可以进行并发编程,但是难度很大.以前,并发性软件的编写.调试和维护都很难,这导致很多开发人员为图省事放弃了并发编程.新版.NET 中的程序库和语 ...

  6. Java并发编程、多线程、线程池…

    <实战java高并发程序设计>源码整理https://github.com/petercao/concurrent-programming/blob/master/README.md Ja ...

  7. Java并发编程之多线程

    线程 进程/线程/协程/管程 进程:操作系统会以进程为单位,分配系统资源(CPU时间片.内存等资源),是资源分配的最小单位 进程间通信(IPC): 管道(Pipe) 命名管道(FIFO) 消息队列(M ...

  8. Java并发编程,多线程[转]

    Java并发编程 转自:http://www.cnblogs.com/dolphin0520/category/602384.html 第一个例子(没有阻塞主线程,会先输出over): package ...

  9. 4、Java并发性和多线程-并发编程模型

    以下内容转自http://ifeve.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9E%8B/: 并发系统可以采用多种并发编程模型来实现. ...

随机推荐

  1. Coursera课程笔记----计算导论与C语言基础----Week 12

    期末编程测试(Week 12) Quiz1 判断闰年 #include <iostream> using namespace std; int main() { int year; cin ...

  2. Appium+Python-项目实践一

    一.前言                            前面讲了环境搭建和常用的元素定位,后续会持续以项目实践的方式去慢慢学习以及整理各方面的知识点,具体不会详细阐述,但会贴上完整代码,想要了 ...

  3. [hdu1085]生成函数

    题意:给a个1.b个2.c个5,求不能构成最小的数 思路: 先求1能构成的所有数,2能构成的所有数,5能构成的所有数,它们的方法数显然都是1,现在考虑把3者结合在一起,由于结果为和的形式,而又是循环加 ...

  4. vscode调试webpack的启动和打包部署过程,nodejs调试

    launch.json ``` {   // 使用 IntelliSense 了解相关属性.    // 悬停以查看现有属性的描述.   // 欲了解更多信息,请访问: https://go.micr ...

  5. web scraper插件爬虫进阶(能满足非技术人员的爬虫需求,建议收藏!!!!)

    为了照顾更多的小伙伴,大家的学习能力及了解程度都不同,因此大家可以通过以下目录来有选择性的学习,节约大家的时间. 备注:  一定要实操!!!            一定要实操!!!           ...

  6. 【Leetcode】164. Maximum Gap 【基数排序】

    Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...

  7. 最短路径——floyd算法代码(c语言)

    最短路径问题 昨天自己试了试写一下dijkstra的算法博客 dijkstra链接在这← 今天来更floyd算法,感觉非常简单果然暴力才是解决一切的王道 一.总体思想 floyd算法就是每一次从邻接矩 ...

  8. 「雕爷学编程」Arduino动手做(17)---人体感应模块

    37款传感器和模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器与模块,依照实践出真知(动手试试)的理念,以学习和交流为目的,这里准备 ...

  9. 把iview中的table组件写成了一个公用组件,在另一个组件里去引用它的时候rander函数里的this指向不正确

    在vue项目里使用iview制作后台管理系统时,由于有多个页面都需要用到table组件,所以就把table写到了一个公共组件里,在其他页面去引用它,但是这时会发现一个问题,就是render函数里的th ...

  10. 字符串 kmp算法 codeforce 625B 题解(模板)

    题解:kmp算法 代码: #include <iostream>#include <algorithm>#include <cstring>#include < ...