首页 文章 精选 留言 我的

精选列表

搜索[java],共10000篇文章
优秀的个人博客,低调大师

Java高并发秒杀Api-业务分析与DAO层构建1

章节目录 1.为什么使用Spring+Spring MVC+Mybatis 2.秒杀业务特性 3.秒杀分析过程、优化思路 4.相关技术介绍 5.基于Maven创建项目 6.秒杀业务分析 7.秒杀事务的难点分析 8.实现秒杀的哪些功能 1.为什么使用Spring+Spring MVC+Mybatis 框架易于使用、轻量级 对业务代码侵入性低 成熟的社区与资料 2.秒杀业务特性 秒杀业务场景具有典型的"事务"特性 秒杀、红包类需求越来越常见,对竞争资源的访问 面试常问的问题 3.相关技术介绍 MySQL 表设计 SQL技巧 事务、行级锁 MyBatis DAO层设计与开发 MyBatis 合理使用 MyBatis 与 Spring整合 Spring Spring Ioc 整合Service Spring 声明式事务使用 Spring MVC Restful 接口设计与使用 框架运作流程 Controller 设计技巧 前端 交互设计 BootStrap Jquery 高并发 高并发点和高并发分析 优化思路并实现 4.基于Maven创建项目 1.maven命令创建web项目骨架 mvn archetype:generate -DgroupId=org.seckill -DartifactId=seckill - DarchetypeArtifactId=maven-archetype-webapp 5.秒杀业务分析 如下图所示: 秒杀业务系统流程分析 所以秒杀业务的核心是对库存的处理。 用户针对库存处理的业务分析用户的秒杀过程 需要减库存->记录购买明细->组成完整事务->数据持久化 如下图所示: 用户秒杀过程 用户购买行为 记录谁购买成功了->成功的时间及有效期->付款、发货信息 为什么需要事务 事务不完整导致的数据一致性问题 如上图所示 1.减了库存,但是没有用户的购买明细,那么就会出现50个商品,但是购买明 细小于50个,到时候发货会发现有些许商品滞留在仓库中,此种情况属于少卖 的情况。 2.记录了明细但是没有减库存,就会发现订单量比商品量要多,出现超卖的情 况,还有一种情况也会导致超卖,多个用户并发修改库存,加入库存量为1,这 个时候多个用户同时去减库存(经过库存量>0的验证),会导致库存为负数, 多个用户抢到同一个商品,这种情况下也会导致超卖发生。 数据落地方案 MySQL VS NoSQL NoSQL非关系型数据库在事务的支持上并没有关系型数据库可靠。 所以归根结底事务机制依然是目前最可靠的落地方案。 6.秒杀事务难点分析 6.1 难点问题-竞争 竞争问题-并发冲突修改 解决方案是采用数据库innodb引擎提供的 事务及 行级锁。 用户减库存的事务流程: begin; update 库存数量; insert 购买明细; commit; 行级锁 如下如所示: 行级锁 情景分析: 在事务执行过程中,mysql默认的repeateable read 隔离级别会在写操作发生的 行上加上行级锁(非记录加锁,而是在对应索引上加锁,上图中的update加锁 发生在id上),多个写请求并发更新同一行记录会产生如下问题: 因为行级锁在事务结束之后才能释放锁,可能会导致锁等待的发生。数据库吞吐率(事务处理能力)会降低。 所以秒杀的难点是什么?秒杀的难点是如何高效的处理竞争-如何在保证数据一致性的情况下高效的处理竞争 8.实现秒杀的哪些功能 1.秒杀接口暴露 浏览器插件获取秒杀接口,通过脚本去秒杀,保护秒杀接口的一种手段。 2.执行秒杀的操作 执行秒杀的业务逻辑 3.秒杀查询,商品详情页查询。 其实市面上最主要的几个秒杀思路是: 1.直接在数据库层面做秒杀 2.缓存中存储库存,用户秒杀请求是将缓存中库存与数据库中库存数据同时进行减库存的过程,保证数据一致性是一个难点。 3.缓存中存储有效的减库存操作,队列减库存的的请求依次顺序执行数据库减库存、生成订单明细事务(操作),如小米。

优秀的个人博客,低调大师

Java内存模型-指令重排序&顺序一致性

章节目录 1.重排序定义 2.数据依赖性 3.as-if-serial语义 4.程序顺序规则 5.JMM 参考 顺序一致性内存模型的实践规范 1.重排序定义 重排序是指编译器和处理器为优化程序性能而对指令序列重新排序的一种手段。 2.数据依赖性 如果两个操作访问同一个变量,且两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性。 如下表所示,是我们常见的数据依赖性场景: 操作模式 代码示例 说明 store->load a=1;b=a; 写一个变量后,再读这个位置 store->store a=1;a=2 写一个变量之后,再写这个变量 load->store a=b;b=1 读一个变量之后,再写这个变量 注意: 上述指令重排序之后,执行结果就会发生变化,所以编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。仅针对于单个处理器中执行的指令序列和单个线程中执行的操作。 3.as-if-serial 语义 对于不存在数据依赖性的操作可以做指令重排序。as-if-serial语义把单线程程序保护了起来。 4.程序顺序规则 如果A happens-before B,注意happens-before定义的不是A,B操作执行的顺序是A先B后,,而是A操作的结果对B操作的结果可见,且A操作的结果按顺序排在B操作结果之前,所以进行指令重排序必须保证的前提是不改变程序执行结果。 5.JMM 参考 顺序一致性内存模型的实践规范 1.JMM采用共享内存模型通过通过控制共享内存与每个线程本地内存之间的交互,来提供内存可见性保证。 2.JMM通过指令重排序来优化程序执行性能,但不正确的重排序会破坏多线程程序的语义,程序运行结果出现非预想的情况。 3.JMM参考顺序一致性内存模型,(但不能完全实现,比如在非同步多线程程序下),来对正确同步的多线程程序做了如下保证-程序的执行结果与该程序在顺序一致性内存模型中的执行结果相同,但正确同步的多线程程序在执行过程中可以对临界区内不存在数据依赖的指令行进行重排序,以在保证执行结果正确的情况下通过指令重排序对程序运行性能做提升。

优秀的个人博客,低调大师

java并发编程实战 第八章 线程池的使用

一、在任务与执行策略直接的隐性耦合 Executor框架可以将任务的提交与任务的执行策略解耦。有些类型的任务需要明确地指定执行策略,包括: 依赖性任务 大多数行为正确的任务都是独立的:他们不依赖于其他任务的执行时序、执行结果或其他效果。当在线程池中执行独立的任务时,可以随意修改线程池大小和配置。如果提交给线程池的任务需要依赖其他任务,那就隐含的给执行策略带来了约束,此时必须小心维持执行策略,一般产生活跃性问题。 使用线程封闭机制的任务 与线程池相比,但线程的Executor能够对并发性作出更强的承诺,他们能确保任务不糊并发的执行,使你能够放宽代码对线程安全的要求。对象可以封闭在线程中,使得在线程执行任务访问对象时不需要同步。使用场景:任务执行Executor是单线程的 对响应时间敏感的任务 GUI应用程序对响应时间敏感,需要用户点击按钮后尽可能快反馈结果。如果一个运行时间较长的任务提交到单线程中,或将多个运行时间较长的任务提交到只包含少量线程的线程池中,那么将降低由改Executor管理服务的响应性。 使用ThreadLocal的任务 ThreadLocal使每个线程都可以拥有某个变量的一个私有“版本”。然而只要条件允许,Executor可以自由的复用这些线程。在标准的Executor中,当执行需求较低时将回收空闲线程,当需求增加时将添加新的线程,并且如果从任务中抛出异常,那么将使用一个新的工作者线程替代异常线程。只有当线程本地值的生命周期受限于任务的生命周期时,在线程池的线程中使用ThreadLocal才有意义,而在线程池的线程中不应该使用ThreadLocal在任务之间传递值。 只有当任务都是同类型的并且相互独立时,线程池的性能才能达到最佳。如果将允许时间较长的与较短的任务混合在一起,除非线程池很大,否则将可能造成“拥塞”。如果提交的人依赖于其他任务,那么除非线程池无限大,否则将可能“死锁”。 1、线程饥饿死锁 在线程池中,如果任务依赖于其他任务,那么可能产生死锁。如果所有正在执行任务的线程都由于等待其他仍处于工作队列的任务而阻塞,这种现象称为线程饥饿死锁。只要线程池中的任务需要无限期等待一些必须由池中其他任务才能提高的资源或条件,除非线程池足够大,否则将发生线程饥饿死锁。 2、运行时间较长的任务 如果任务阻塞时间过长,即使不出现死锁,线程池的响应性也会变得糟糕。增加了线程池的堵塞,还增加了执行时间较短任务的服务时间。可以使用限时等待解决上述问题。 二、设置线程池的大小 三、配置ThreadPoolExecutor ThreadPoolExecutor是一个灵活的、稳定的线程池。 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler); 1、线程的创建与销毁 线程池基本大小(corePoolSize)、最大大小(maximumPoolSize)、存活时间、等因素共同负责线程的创建与销毁。基本大小:线程池目标大小,即在没有任务执行时线程池大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。最大大小:表示可以同时活动的线程数量的上限。如果某线程的空闲超过了存活时间,那么将标记为可回收,并且当线程池的当前大小超过了基本大小时,这个线程将被终止。 2、管理队列任务 ThreadPoolExecutor允许提供一个BlockingQueue来保存等待执行的任务,基本的排队方法有:无界队列、有界队列、同步移交(Synchronous Handoff)。newFixedThreadPool和newSingleThreadExecutor默认使用无界的linkedBlockingQueue。如果所有工作者线程都处理忙碌状态,任务将在队列中等候。如果任务持续快速到达,并且超过了线程池处理速度,队列将无限制增加。使用有界队列更稳妥,可以避免资源耗尽。有界队列工作时,队列大小与线程池的大小必须一起调节。如果线程池较小队列较大,那么有助于减少内存使用量,降低CPU使用率,减少上下文切换,但可能限制了吞吐量。 对于非常大的或者无界的线程池,可以通过使用SynchronousQueue来避免任务排队,直接将任务从生产者交给工作者线程。SynchronousQueue并不是真正的队列,而是一种在线程之间进行移交的机制。要将一个元素放入其中,必须有另一个线程正在等待接受这个元素。如果没有,并且线程池的当前大小小于最大值,那么将创建一个新线程,否则根据饱和策略,这个任务将被拒绝。 3、饱和策略 当有界队列被填满后,饱和策略开始发挥作用。中止策略(AbortPolicy)是默认的饱和策略,该策略将抛出未检查的RejectedExecutionException。可以被捕获,然后处理自己代码。当新提交的任务无法保存到队列中等待执行时,抛弃策略将悄悄抛弃任务,抛弃最旧的(DiscardOldest)策略则会抛弃下一个将被执行任务,然后尝试重新提交新的任务。调用者运行策略(CallerRunsPolicy)实现了一种调节机制,既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量。 4、线程工厂 每当线程池需要创建一个线程时,都是通过线程工厂方法来完成的。默认的线程工厂方法将创建一个新的、非守护线程,并且不包含特殊配置信息。

优秀的个人博客,低调大师

java中驼峰命名和下划线命名互转方法(代码实现)

1 /** 2 * 将驼峰式命名的字符串转换为下划线大写方式。如果转换前的驼峰式命名的字符串为空,则返回空字符串。 3 * 例如:HelloWorld->HELLO_WORLD 4 * @param name 转换前的驼峰式命名的字符串 5 * @return 转换后下划线大写方式命名的字符串 6 */ 7 public static String underscoreName(String name) { 8 StringBuilder result = new StringBuilder(); 9 if (name != null && name.length() > 0) { 10 // 将第一个字符处理成大写 11 result.append(name.substring(0, 1).toUpperCase()); 12 // 循环处理其余字符 13 for (int i = 1; i < name.length(); i++) { 14 String s = name.substring(i, i + 1); 15 // 在大写字母前添加下划线 16 if (s.equals(s.toUpperCase()) && !Character.isDigit(s.charAt(0))) { 17 result.append("_"); 18 } 19 // 其他字符直接转成大写 20 result.append(s.toUpperCase()); 21 } 22 } 23 return result.toString(); 24 } 1 /** 2 * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 3 * 例如:HELLO_WORLD->HelloWorld 4 * @param name 转换前的下划线大写方式命名的字符串 5 * @return 转换后的驼峰式命名的字符串 6 */ 7 public static String camelName(String name) { 8 StringBuilder result = new StringBuilder(); 9 // 快速检查 10 if (name == null || name.isEmpty()) { 11 // 没必要转换 12 return ""; 13 } else if (!name.contains("_")) { 14 // 不含下划线,仅将首字母小写 15 return name.substring(0, 1).toLowerCase() + name.substring(1); 16 } 17 // 用下划线将原始字符串分割 18 String camels[] = name.split("_"); 19 for (String camel : camels) { 20 // 跳过原始字符串中开头、结尾的下换线或双重下划线 21 if (camel.isEmpty()) { 22 continue; 23 } 24 // 处理真正的驼峰片段 25 if (result.length() == 0) { 26 // 第一个驼峰片段,全部字母都小写 27 result.append(camel.toLowerCase()); 28 } else { 29 // 其他的驼峰片段,首字母大写 30 result.append(camel.substring(0, 1).toUpperCase()); 31 result.append(camel.substring(1).toLowerCase()); 32 } 33 } 34 return result.toString(); 35 } 参考博客:http://jhonnnnnn.iteye.com/blog/2261298我的GitHub地址: https://github.com/heizemingjun 我的博客园地址: http://www.cnblogs.com/chenmingjun 我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun Copyright ©2018 黑泽明军 【转载文章务必保留出处和署名,谢谢!】

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册