《Java 高并发》01 高并发基本概念

基本概念

同步和异步

同步和异步通常是用来形容一次方法调用。

同步方法调用一旦开始,调用者必须等到方法返回才能继续执行后续操作。

异步方法调用更像一个消息传递,一旦开始,方法调用就会立即返回,调用者就可以继续后续的操作。异步方法通常会在另外一个线程中"真实"执行,整个过程不会影响调用者的工作。

举例:到了饭点,我们点外卖,下单成功之后等待外卖小哥送餐。这就是同步调用。 不过,为了学习,我们在下单成功之后看了会《Java 从入门到放弃》书籍,边等待外卖小哥送餐。这就是异步调用。

并发和并行

并发和并行两个概念很容易被混淆。他们都可以表示两个或者多个任务一起执行,但是偏重点有些不同。并发偏重于多个任务交替执行,而多个任务之间有可能还是串行的。而并行是真正意义上的"同时执行"。

 

严格来说,并行的多个任务是真实的同时执行,而对于并发来说,这个过程值是交替执行。一会儿执行A,一会儿执行B,系统会不停地在两者间切换。但是对于外部观察者来说,即使多个任务之间是串行并发的,也会造成多任务间是并行执行的错觉。

举例:三个人同时吃三个苹果,这句是并行。而一个吃三个苹果,这就是并发,他需要来回切换。

临界区

临界区用来表示一种公共资源或者说是共享数据,可以被多个线程使用。但是每一次,只能有一个线程使用它,一旦临界区资源被占用,其他线程想要使用这个资源,则必须等待。

举例:会议室开会,当有人正在使用会议室,而这个时候你又想要使用这个会议室,就必须等他们会议结束才能使用。

阻塞和非阻塞

阻塞和非阻塞通常是用来形容多线程间的相互影响。比如当临界区资源被占用时,那么其他需要需要使用这个临界区资源的线程就必须等待,等待会导致线程挂起,这种情况就是阻塞。非阻塞的意思与之相反,它强调没有一个线程可以妨碍其他线程执行。

死锁、饥饿、和活锁

死锁、饥饿和活锁都属于多线程的活跃性问题。

死锁:多个进程对公共资源的相互竞争,导致循环等待的现象。比如:A->B->C->A,互相竞争,循环等待。

饥饿:指某一个线程或者多个线程因为某种原因无法获得所需要的资源,导致一直无法执行。比如:线程优先级低,导致高优先级的线程不断抢占它需要的资源,导致低优先级的线程无法工作。举例:在自然界中,母鸟喂食。由于雏鸟很多,而食物有限,雏鸟之间的事务竞争可能非常厉害,小雏鸟因为经常抢不到食物,有可能会被饿死。

活锁:活锁恰恰与死锁相反,死锁是大家都拿不到资源都占用着对方的资源,而活锁是拿到资源却又相互释放不执行。当多线程中出现了相互谦让,都主动将资源释放给别的线程使用,这样这个资源在多个线程之间跳动而又得不到执行,这就是活锁。举例:两个人迎面走来时,有时候因为有事比较急,而为了快速通过会避让对方先行。恰好对方也为了能快速通过礼让你先行,结果撞上了。于是乎,都意识到了这个问题,希望尽快避让对方,你向右他向左,结果又撞上了。

并发级别

由于临界区的存在,多线程之间的并发必须收到控制。根据控制并发的策略对并发的级别进行分类,大致为阻塞无饥饿无障碍无锁无等待

阻塞

一个线程是阻塞的,那么在其他线程释放资源之前,当前线程无法继续执行。当使用 Synchronized 关键字或者重入锁时,我们得到的就是阻塞线程。

无饥饿

如果线程之间是有优先级的,那么线程调度的时候总是会倾向于满足高优先级的线程。也就是说,对于同一个资源的分配,是不公平的。那就出现了公平和非公平两种情况。对于非公平锁来说,系统允许优先级高的线程插队。这样有可能导致优先级低的线程产生饥饿。但如果锁是公平的,满足先来后到,那么接就不会产生,不论新来的线程优先级高低,想要获得资源就必须乖乖排队,那么所有的线程都有机会执行。

无障碍

无障碍是一种最弱的非阻塞调度。两个线程如果是无障碍的执行,那么他们不会因为临界区的问题导致一方被挂起。换言之,大家都可以大摇大摆地进入临界区了。对于无障碍的线程来说,一旦检测到数据被修改坏了,它会立即对自己所做的修改进行回滚,确保数据的安全。

如果说阻塞的控制方式是悲观策略,那么非阻塞的调度就是一种乐观的策略。它任务多个线程之间很有可能不会发生冲突,或者说这种概率不大。因此大家都应该无障碍的执行,但是一旦检测到冲突,就应该进行回滚。但是无障碍的多线程程序并不一定能够顺畅的运行,因为当临界区中存在严重的冲突时,所有的线程可能都会不断地回滚自己的操作,而没有一个线程可以走出临界区。这种情况会影响系统的正常执行。所有,我们希望在这一堆线程中,至少有一个线程能够在有效的时间内完成自己的操作,从而退出临界区。至少这样可以保证系统不会在临界区中进行无线的等待。

一种可行的无障碍实现可以依赖一个"一致性标记"来实现。线程在操作之前,线程读取并保存这个标记,在操作完成后,在此读取,检查这个标记是否被更改过,如果两者是一致的,则的说明资源访问没有冲突。如果不一致,则说明资源可能在操作过程中与其他线程冲突,需要重试操作。

无锁

无锁的并行都是无障碍的。在无锁的情况下,所有的线程都能尝试对临界区进行访问,但是不同的是,无锁的并发保证必然有一个线程能够在有限步内完成操作离开临界区。

无等待

无锁只要求有一个线程可以在有限步内完成操作,而无等待则是在无锁的基础上更进一步进行扩展。它要求所有的线程都必须在有限步内完成,这样就不会引起饥饿问题。如果限制这个步骤上限,还可以进一步分解为有界无等待和线程数无关的无等待几种,他们之间的区别只是对循环次数的限制不同。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/273552.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android之Http网络编程(四)

前面几篇博文简单的介绍了一些常见的Http的操作,这些操作几乎都是在新开的线程中进行的网络请求,并在日志中打印出获取到的网络数据。那么,问题来了!(呃~感觉下一句是蓝翔有木有?)如何在把获取到…

《Java 高并发》02 多线程的特性

多线程的三大特性:原子性、可见性和有序性。 原子性 原子性是指一个操作或者多个操作,一旦开始就不会被其他线程干扰,即使是在多个线程一起执行的情况下也不会被干扰。或者不执行。 原子性主要是为了保证数据一致,线程安全问题…

U3D-FSM有限状态机的简单设计

http://coder.beitown.com/archives/592 在之前的文章里介绍了一个基础U3D状态机框架(Unity3D游戏开发之状态流框架)即大Switch的枚举状态控制。这种方法虽然容易理解,编程方法也相对简单,但是弊端是当状态变得复杂之后&#xff0…

《Java 高并发》04 线程的基本操作

新建线程 新建线程很简单。只要使用new 关键字创建一个线程对象,并且调用 start 方法启动线程。 Thread t new Thread(); t.start();注意:run 方法不是用来启动线程。如果调用 run 方法它只会作为普通方法来执行,而不会开启线程执行。 终止…

Dispatch 方法简介

后台执行 dispatch_async(dispatch_get_global_queue(0, 0), ^{ //后台程执行 something; }); 主线程执行 dispatch_async(dispatch_get_main_queue(), ^{// 主线程执行something; }); 一次性执行 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // 主…

linux杂七杂八整理

64系统里执行32位程序: 1、在64系统里执行32位程序如果出现/lib/ld-linux.so.2: bad ELF interpreter: No such file or directory,安装下glic即可sudo yum install glibc.i6862、error while loading shared libraries: libz.so.1: cannot …

《Java 高并发》05 线程的基本操作

volatile 与 Java 内存模型 Java 内存模型都是围绕着原子性、有序性和可见性展开的。为了在适当的场合,确保线程间的原子性、有序性和可见性。Java 使用了一些特许的操作或者关键字来申明、告诉虚拟机,在这个地方,要尤其注意,不能…

mybatis 2 -常用数据操作

1、写入数据并获取自增ID XML配置&#xff1a; <!-- 写入数据获取自增ID --><insert id"insertLog" parameterType"com.mamaguwen.entity.sys_loginlog" useGeneratedKeys"true" keyProperty"logid">insert into sys_…

Spring常用的的注解对应xml配置详解

Component(value"")注解&#xff1a;组件 标记在类上&#xff0c;也可以放在接口上注解作用&#xff1a;把AccountDao实现类对象交由Spring IOC容器管理 相当于XML配置文件中的Bean标签 <bean id"userAnnonMapper" class"com.spring.mapper.User…

安卓模拟器bluestacks mac地址修改教程

http://szmars2008.blog.163.com/blog/static/118893702201373181349348/ 转载于:https://www.cnblogs.com/prayer521/p/4069037.html

Docker 搭建 ELK 日志系统,并通过 Kibana 查看日志

Docker 搭建 ELK 日志系统,并通过 Kibana 查看日志 docker-compose.yml version: 3 services:elasticsearch:image: elasticsearch:7.7.0 #镜像container_name: elasticsearch #定义容器名称restart: always #开机启动&#xff0c;失败也会一直重启environment:- "cl…

蟠桃记

Problem Description 喜欢西游记的同学肯定都知道悟空偷吃蟠桃的故事&#xff0c;你们一定都觉得这猴子太闹腾了&#xff0c;其实你们是有所不知&#xff1a;悟空是在研究一个数学问题&#xff01; 什么问题&#xff1f;他研究的问题是蟠桃一共有多少个&#xff01; 不过&#…

Spring 定时任务动态管理

管理 Spring 中定时任务 pom.xml <properties><hutool.version>5.6.6</hutool.version><lombok.version>1.18.20</lombok.version><spring-boot.web.version>2.2.10.RELEASE</spring-boot.web.version> </properties><de…

高效率Oracle SQL语句

1、Where子句中的连接顺序&#xff1a; ORACLE采用自下而上的顺序解析WHERE子句。 根据这个原理&#xff0c;表之间的连接必须写在其他WHERE条件之前&#xff0c; 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾。 举例&#xff1a; (低效) select ... from table1…

RabbitMQ Management:Management API returned status code 500

错误显示&#xff1a; 解决方案&#xff1a; 因为是使用docker 容器安装的&#xff0c;所有需要进入容器 docker exec -it rabbitmq /bin/bash进入目录 cd /etc/rabbitmq/conf.d/执行命令 echo management_agent.disable_metrics_collector false > management_agent.dis…

Android JNI和NDK学习(5)--JNI分析API

Java类型和本地类型对应 在如下情况下&#xff0c;需要在本地方法中应用java对象的引用&#xff0c;就会用到类型之间的转换&#xff1a; java方法里面将参数传入本地方法&#xff1b;在本地方法里面创建java对象&#xff1b;在本地方法里面return结果给java程序。Java基本类型…

RabbitMq 消费失败,重试机制

方案一&#xff1a; 本地消息表 定时任务 本地消息表&#xff1a;主要用于存储 业务数据、交换机、队列、路由、次数 定时任务&#xff1a;定时扫描本地消息表&#xff0c;重新给业务队列投递消息。 具体思路&#xff1a;业务队列消费失败时&#xff0c;把 业务数据、交换机、…

Android常用的工具类

主要介绍总结的Android开发中常用的工具类&#xff0c;大部分同样适用于Java。目前包括HttpUtils、DownloadManagerPro、ShellUtils、PackageUtils、 PreferencesUtils、JSONUtils、FileUtils、ResourceUtils、StringUtils、 ParcelUtils、RandomUtils、ArrayUtils、ImageUtils…

0. Spring 基础

BeanDefinition BeanDefinition 表示 Bean 定义&#xff1a; Spring根据BeanDefinition来创建Bean对象&#xff1b;BeanDefinition有很多的属性用来描述Bean&#xff1b;BeanDefiniton是Spring中非常核心的概念。BeanDefiniton中重要的属性&#xff1a; a. beanClass&#xf…

1. Spring 源码:Spring 解析XML 配置文件,获得 Bena 的定义信息

通过 Debug 运行 XmlBeanDefinitionReaderTests 类的 withFreshInputStream() 的方法&#xff0c;调试 Spring 解析 XML 配置文件&#xff0c;获得 Bean 的定义。 大体流程可根据序号查看&#xff0c;xml 配置文件随便看一眼&#xff0c;不用过多在意。 <?xml version&qu…