对于我们开发的网站,如果网站的访问量非常大的话,我们就需要考虑相关的并发访问问题了。而且并发问题也是中高级工程师面试中必问的问题,今天我们就来系统学习一下。

为了更好的理解并发和同步,我们先学习两个重要的概念:同步和异步。

1、同步和异步的区别和联系

所谓同步,可以理解为在执行完一个函数或方法之后,一直等待系统返回值或消息,这时程序是处于阻塞状态的,只有接受到返回值或消息之后才往下执行其他的命令。

所谓异步,执行外函数或方法之后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,从而完成一个完整的流程。

同步在一定程度上可以看作是单线程,这个线程请求一个方法之后就等待这个方法给他回复,否则就不往下执行

异步在一定程度上可以看作多线程,请求一个方法之后就不管了,继续执行其他的方法

同步就是一件事,一件事一件事的做。

异步就是,做一件事,不影响做其他的事情。

对于java程序而言,我们会经常听到同步关键字synchronized,假如这个同步的监事对象是类,那么当一个对象访问这个类里面的同步方法的时候,其他的对象也想访问这个同步方法就会进入阻塞状态,只有等前一个对象执行完该同步方法,当前对象才能继续执行该方法,这就是同步。相反,如果方法前没有同步关键字修饰的话,那么不同的对象就可以在同一时间访问同一个方法,这就是异步。再补充一下脏数据和不可重复读的概念。

2、脏数据和不可重复读

脏数据:
脏读就是指,当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务访问并使用了这个数据。因为这个数据还没有提交,那么另外一个事务读到的数据就是脏数据(dirty data),依据脏数据所做的操作可能是不正确的。

不可重复读:
指在数据库访问中,一个事务范围内两个相同的查询却返回了不同的数据。这是由于查询时系统中其它事务修改的提交引起的。一种更容易理解的说法是:在一个事务内,多次读取同一数据。在这个事务还没结束时,另一个事务也访问该数据。那么,在第一个事务的两次读数据之间,由于第二个事务的修改,导致第一个事务两次读到的数据可能不同,因此成为不可重复读,即原始读取不可重复。

3、如何处理并发和同步

今天学习的处理并发和同步问题主要是通过锁机制

锁机制有两个层面:
一种是代码层面上的,如java中的同步锁,典型的就是同步关键字synchronized和lock
http://www.cnblogs.com/xiohao/p/4151408.html
http://www.cnblogs.com/xiohao/p/4151924.html
http://blog.csdn.net/lmb55/article/details/46279155

另一种是数据库层面上的,比较典型的就是悲观锁和乐观锁
有关悲观锁和乐观锁的内容请参看:http://blog.csdn.net/lmb55/article/details/78266667

4、常见java并发同步案例分析

案例一:订票系统案例,某航班只有一张机票,假定有1W个人打开你的网站来订票,问你如何解决并发问题(可扩展到任何高并发网站要考虑的并发读写问题)

问题,1W个人来访问,要求票没出去前必须保证大家都能看到票,不可能一个人在看到票的时候别人就不能看到。但是最后到底谁能抢到,那得要看这个人的“运气”了(网络快慢等)

首先我们容易想到和并发相关的几个方案:

锁同步更多指的是应用程序的层面,多个线程进来,只能一个一个的访问。除了Java中的对象锁,还有另外一个层面—数据库锁。如果是分布式系统,显然只能使用数据库端的锁来实现。

假定我们采用了同步机制或者数据库物理锁机制,如果保证1W个人还能同时看到有票,这显然会牺牲性能,在高并发网站中是不可取的。

由此来看,采用乐观锁即可解决此问题。乐观锁是在不锁表的情况下,利用业务的控制来解决并发问题,这样既保证数据的并发可读性又保证数据的排他性,保证性能的同时也解决了并发带来的脏数据问题

hibernate如何实现乐观锁:

前提:在现有表中增加一个冗余字段,long类型的version版本号。

原理:
1)只有当前版本号>=数据库表的版本号才能提交
2)提价成功后,版本号version++

实现很简单:在orgmapping增加一个属性optimistic-lock=”version”即可,以下是样例片段:

<hibernate-mapping>
<class name="com.stock.ABC" optimistic-lock="version" table="T_Stock" schema="STOCK">
</hibernate-mapping>

案例二:股票交易系统、银行系统,大数据量你是如何考虑的

首先,股票交易系统的行情表,每几秒钟就有一个行情记录产生,一天下来就有(假定行情3s一个)股票数量*20*60*6条记录,一个月下来这个表的记录数量多大?Oracle中一张表的记录数超过100W之后查询性能就很差了,如何保证系统性能?

再比如,中国移动有上亿的用户量,表如何设计?把所有数据存到一张表?

所以,大数据量的系统,必须考虑表拆分(表名不一样,但是结构完全一样),通常用到的有以下几种方式(视情况而定):

1)按业务分。比如手机号的表,我们可以考虑130开头的一个表,131开头的另一个表,以此类推。

2)利用Oracle的表拆分机制做分表

3)如果是交易系统,我们可以考虑按时间轴拆分,当日数据一个表,历史数据弄到其它表。这里历史数据的报表和查询不会影响当日交易。

当然,表拆分后我们的应用要做相应的适配。单纯的orgmapping就得改动了。比如部分业务要通过存储过程等。

此外,我们还要考虑缓存

这里的缓存,指的不仅是hibernate,hibernate本身提供了一级二级缓存。这里的缓存独立于应用,依然是内存的读取。假如我们能减少数据库频繁的访问,那对系统肯定大大有利。比如一个电子商务系统的商品搜索,如果某个关键字的商品经常被搜,那就可以考虑把这部分商品列表存放到缓存(内存)中去,这样不用每次访问数据库,性能大大增加。

简单的缓存我们可以理解为自己做一个HashMap,把经常访问的数据做一个key,value是第一次从数据库搜索出来的值,下次访问就可以从map中读取,而不需要读数据库。目前专业些的有独立缓存框架比如memcached等,可独立部署成一个缓存服务器。

redis实现分布式锁:
http://blog.csdn.net/lmb55/article/details/78235768
Redis实现秒杀:
http://blog.csdn.net/lmb55/article/details/78266905

5、常见的提高高并发下访问效率的手段

首先要了解高并发的瓶颈在哪里?

1)可能是服务器网络带宽不够
2)可能是web线程连接数不够
3)可能是数据库连接查询上不去

根据不同的情况,解决思路也不同

1)像第一种情况可以增加网络带宽,DNS域名解析分发多台服务器。
2)负载均衡,前置代理服务器nginx、apache等等。
3)数据库查询优化,读写分离,分表等等。

最后复制一些在高并发下面常常需要处理的内容:

1)尽量使用缓存,包括用户缓存、信息缓存等,多花点内存来做缓存。可以大量减少与数据库的交互,提高性能。
2)用jprofiler等工具找出性能瓶颈,减少额外开销。
3)优化数据库查询语句,减少直接使用hibernate等工具的直接生成语句(仅耗时较长的查询做优化)
4)优化数据库结构,多做索引,提高查询效率
5)统计的功能尽量做缓存,或按每天统计或者定时统计相关报表,避免需要时进行统计的功能。
6)能使用静态页面的地方尽量使用静态页面,减少容器的解析(尽量将动态内容内容生成静态html显示)。
7)解决以上问题后,使用服务器集群来解决单台的瓶颈问题。

【Java并发编程】java高并发的解决方案(一)相关推荐

  1. 《Java并发编程入门与高并发面试》or 《Java并发编程与高并发解决方案》笔记

    <Java并发编程入门与高并发面试>or <Java并发编程与高并发解决方案>笔记 参考文章: (1)<Java并发编程入门与高并发面试>or <Java并发 ...

  2. Java 高并发_JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过!...

    JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过! 1.JPG (37.82 KB, 下载次数: 0) 2018-12-3 09:40 上传 2.JPG (28 ...

  3. 01 - Java并发编程与高并发解决方案笔记-基础篇

    01 - Java并发编程与高并发解决方案笔记-基础篇 基础篇很重要!很重要!很重要!!!一定要理解和认真思考. 01 - Java并发编程与高并发解决方案笔记-基础篇 1.课程准备 2.并发编程基础 ...

  4. JavaWeb 并发编程 与 高并发解决方案

    在这里写写我学习到和自己所理解的 Java高并发编程和高并发解决方案.现在在各大互联网公司中,随着日益增长的互联网服务需求,高并发处理已经是一个非常常见的问题,在这篇文章里面我们重点讨论两个方面的问题 ...

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

    知识点 线程安全,线程封闭,线程调度,同步容器,并发容器,AQS,J.U.C,等等 高并发解决思路与手段 扩容:水平扩容.垂直扩容 缓存:Redis.Memcache.GuavaCache等 队列:K ...

  6. 高并发编程_高并发编程系列:7大并发容器详解(附面试题和企业编程指南)...

    不知道从什么时候起,在Java编程中,经常听到Java集合类,同步容器.并发容器,高并发编程成为当下程序员需要去了解掌握的技术之一,那么他们有哪些具体分类,以及各自之间的区别和优劣呢? 只有把这些梳理 ...

  7. java高并发解决方案_长文慎入-探索Java并发编程与高并发解决方案

    所有示例代码,请见/下载于 1 基本概念 1.1 并发 同时拥有两个或者多个线程,如果程序在单核处理器上运行多个线程将交替地换入或者换出内存,这些线程是同时"存在"的,每个线程都处 ...

  8. 高并发编程_高并发编程系列:全面剖析Java并发编程之AQS的核心实现

    在并发编程领域,AQS号称是并发同步组件的基石,很多并发同步组件都是基于AQS实现,所以想掌握好高并发编程,你需要掌握好AQS. 本篇主要通过对AQS的实现原理.数据模型.资源共享方式.获取锁的过程, ...

  9. 转:Java并发编程与高并发解决方案(一)

    转: https://blog.csdn.net/m0_37819279/article/details/81154126 首先介绍连接池 1:ExecutorService是Executor直接的扩 ...

  10. Java多线程学习处理高并发问题

    在程序的应用程序中,用户或请求的数量达到一定数量,并且无法避免并发请求.由于对接口的每次调用都必须在返回时终止,因此,如果接口的业务相对复杂,则可能会有多个用户.调用接口时,该用户将冻结. 以下内容将 ...

最新文章

  1. 零基础python入门书籍-浅谈零基础自学python入门书
  2. asp.net ajax 弹不出alert对话框的解决办法
  3. Python教程:如何将list嵌套的list的[]去掉
  4. gdb调试时查看内存
  5. WPF实现物理效果 拉一个小球
  6. 千万别让男朋友穿你的短裙......
  7. Android View的绘制流程简述 Android自定义View(一)
  8. 将已有项目转为se项目_如何将 Java 项目转换成 Maven 项目
  9. RocketMQ高性能通信实现机制源码精读
  10. MySQL基于复制的架构方案
  11. 实战Python:详解利用Python和Pygame实现飞机大战
  12. 【前端面试之缓存】js本地缓存、浏览器缓存、服务器缓存
  13. 自然辩证法与计算机科学的关系,自然辩证法和科学技术有什么关系
  14. 基于JAVA的鲜花店商城平台【数据库设计、源码、开题报告】
  15. 袁帅做了两件意义非凡的事
  16. 高等数学学习笔记——第二十九讲——罗尔定理与拉格朗日中值定理
  17. 断点恢复执行时的设置
  18. 再贴一个Fleaphp相关的
  19. Python3 利用Virustotal API 获取json格式的分析报告
  20. 【LeetCode】1823. 找出游戏的获胜者 Find the Winner of the Circular Game

热门文章

  1. Myeclipse2013下载,安装,破解,介绍(CSDN首发)
  2. python实现蜘蛛功能批量下载手机壁纸
  3. 探讨“临时对象”(temporary object)
  4. FreeBSD基本命令[转]
  5. Dockerfile文件创建centos:7,配置JDK8的环境变量,与运行springboot的jar包,的镜像
  6. 实现一个通用的中英文排序工具
  7. maven(android-maven-plugin3.8.0)打包apk无法启动,apklib依赖包的资源索引出错(R文件与主模块冲突)问题解析
  8. 小程序动画Animation,高度增加动画形式,图标旋转动画形式
  9. Oracle笔记(十四) 用户管理
  10. 快速排序以及基于快排思想的找前k个最大数