<small id='EBPcR3'></small> <noframes id='EvWnQ'>

  • <tfoot id='XeiClN9'></tfoot>

      <legend id='PGb2FxuYw'><style id='50OeUvLCG'><dir id='pXwEKiFZcl'><q id='Bq68vm'></q></dir></style></legend>
      <i id='xjiHcFAn63'><tr id='0DS4'><dt id='uGpoiz'><q id='GaSfT'><span id='DIWsZ'><b id='JzrsY'><form id='QO4pFuj'><ins id='Q5tUP0Rcdr'></ins><ul id='MFe91uyBT'></ul><sub id='Mxm9'></sub></form><legend id='dPn4QR'></legend><bdo id='W9yqd'><pre id='mZJdEtuxs'><center id='K9ubdgZ'></center></pre></bdo></b><th id='m7SHZf2'></th></span></q></dt></tr></i><div id='maFG6PC4Yz'><tfoot id='IW9v'></tfoot><dl id='vPtFud'><fieldset id='LD2jQ'></fieldset></dl></div>

          <bdo id='4JUad'></bdo><ul id='wcKQ4Fe'></ul>

          1. <li id='nseP5'></li>
            登陆

            章鱼彩票app-Java进阶——亿级网站大数据量下的高并发同步解说

            admin 2019-05-14 417人围观 ,发现0个评论
            关于咱们开发的网站,假定网站的拜访量非常大的话,那么咱们就需求考虑相关的并发拜拜访题了。而并发问题是绝大部分的程序员头疼的问题,
            但话又说回来了,已然躲避不掉,那咱们就安然面临吧~今日就让咱们一起来研究一下常见的并发和同步吧。
            为了更好的了解并发和同步,咱们需求先了解两个重要的概念:同步和异步
            1、同步和异步的差异和联络
            所谓同步,能够了解为在履行完一个函数或办法之后,一向等候体系回来值或音讯,这时程序是出于堵塞的,只要接收到
            回来的值或音讯后才往下履行其它的指令。
            异步,履行完函数或办法后,不必堵塞性地等候回来值或音讯,只需求向体系托付一个异步进程,那么当体系接收到回来
            值或音讯时,体系会主动触发托付的异步进程,然后完结一个完好的流程。
            同步在必定程度上能够看做是单线程,这个线程恳求一个办法后就待这个办法给他回复,不然他不往下履行(死心眼)。
            异步在必定程度上能够看做是多线程的(废话,一个线程怎样叫异步),恳求一个办法后,就不管了,持续履行其他的办法。
            同步便是一件事,一件工作一件事的做。
            异步便是,做一件工作,不引响做其他工作。
            例如:吃饭和说话,只能一件事一件事的来,因为只要一张嘴。
            但吃饭和听音乐是异步的,因为,听音乐并不引响咱们吃饭。
            关于Java程序员而言,咱们会经常听到同步关键字synchronized,假定这个同步的监督方针是类的话,那么假定当一个方针
            拜访类里边的同步办法的话,那么其它的方针假定想要持续拜访类里边的这个同步办法的话,就会进入堵塞,只要等前一个方针
            履行完该同步办法后当时方针才干够持续履行该办法。这便是同步。相反,假定办法前没有同步关键字润饰的话,那么不同的方针
            能够在同一时刻拜访同一个办法,这便是异步。
            在弥补一下(脏数据和不可重复读的相关概念):
            脏数据
            脏读便是指当一个事务正在拜访数据,而且对数据进行了修正,而这种修正还没有提交到数据库中,这时,别的一个事务也拜访这个数据,然后运用了这
            个数据。因为这个数据是还没有提交的数据,那么别的一个事务读到的这个数据是脏数据(Dirty Data),依据脏数据所做的操作或许是不正确的。
            不可重复读
            不可重复读是指在一个事务内,屡次读同一数据。在这个事务还没有结束时,别的一个事务也拜访该同一数据。那么,在第一个事务中的两次读数据之间,因为第二个事务的修正,那么第一个事务两次读到的数据或许是不相同的。这样就发作了在一个事务内两次读到的数据是不相同的,因而称为是不可重复读
            2、怎么处理并发和同步
            今日讲的怎么处理并发和同同步问题主要是经过锁机制。
            咱们需求了解,锁机制有两个层面。
            一种是代码层次上的,如java中的同步锁,典型的便是同步关键字synchronized,这儿我不在做过多的解说,
            别的一种是数据库层次上的,比较典型的便是失望锁和达观锁。这儿咱们要点解说的便是失望锁(传统的物理锁)和达观锁。
            失望锁(Pessimistic Locking):
            失望锁,正如其名,它指的是对数据被外界(包含本体系当时的其他事务,以及来自 外部体系的事务处理)修正持保存情绪,因而,
            在整个数据处理进程中,将数据处于确定状况。
            失望锁的完成,往往依托数据库供给的锁机制(也只要数据库层供给的锁机制才干 真实确保数据拜访的排他性,不然,即便在本体系中完成了加锁机制,也无法确保外部系 统不会修正数据)。
            一个典型的倚赖数据库的失望锁调用:
            select * from account where name=”Erica” for update
            这条 sql 句子确定了 account 表中一切契合检索条件( name=”Erica” )的记载。
            本次事务提交之前(事务提交时会开释事务进程中的锁),外界无法修正这些记载。
            Hibernate 的失望锁,也是依据数据库的锁机制完成。
            下面的代码完成了对查询记载的加锁:
            String hqlStr ="from TUser as user where user.name='Erica'";
            Query query = session.createQuery(hqlStr);
            query.setLockMode("user",LockMode.UPGRADE); // 加锁
            List userList = query.list();// 履行查询,获取数据
            query.setLockMode 对查询句子中,特定别号所对应的记载进行加锁(咱们为 TUser 类指定了一个别号 “user” ),这儿也便是对回来的一切 user 记载进行加锁。
            调查运行期 Hibernate 生成的 SQL 句子:
            select tuser0_.id as id, tuser0_.name as name, tuser0_.group_id
            as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex
            from t_user tuser0_ where (tuser0_.name='Erica' ) for update
            这儿 Hibernate 经过运用数据库的 for update 子句完成了失望锁机制。
            Hibernate 的加锁形式有:
            LockMode.NONE : 无锁机制。
            LockMode.WRITE : Hibernate 在 Insert 和 Update 记载的时分会主动获取
            LockMode.READ : Hibernate 在读取记载的时分会主动获取。
            以上这三种锁机制一般由 Hibernate 内部运用,如 Hibernate 为了确保 Update
            进程中方针不会被外界修正,会在 save 办法完成中主动为方针方针加上 WRITE 锁。
            LockMode.UPGRADE :运用数据库的 for update 子句加锁。
            LockMode. UPGRADE_NOWAI章鱼彩票app-Java进阶——亿级网站大数据量下的高并发同步解说T : Oracle 的特定完成,运用 Oracle 的 for
            update nowait 子句完成加锁。
            上面这两种锁机制是咱们在运用层较为常用的,加锁一般经过以下办法完成:
            Criteria.setLockMode
            Query.setLockMode
            Session.lock
            留意,只要在查询开端之前(也便是 Hiberate 生成 SQL 之前)设定加锁,才会
            真实经过数据库的锁机制进行加锁处理,不然,数据现已经过不包含 for update
            子句的 Select SQL 加载进来,所谓数据库加锁也就无从谈起。
            为了更好的了解select... for update的锁表的进程,自己即将以mysql为例,进行相应的解说
            1、要测验确定的状况,能够运用MySQL的Command Mode ,开二个视窗来做测验。
            表的根本结构如下:



            表中内容如下:



            敞开两个测验窗口,在其间一个窗口履行select * from ta for update0
            然后在别的一个窗口履行update操作如下图:


            比及一个窗口commit后的图片如下:


            到这儿,失望锁机制你应该了解一些了吧~

            需求留意的是for update要放到mysql的事务中,即begin和commit中,否者不起作用。
            至所以锁住整个表仍是锁住选中的行
            至于hibernate中的失望锁运用起来比较简略,这儿就不写demo了~感兴趣的自己查一下就ok了~
            达观锁(Optimistic Locking):
            相对失望锁而言,达观锁机制采取了愈加宽松的加锁机制。失望锁大多数状况下依 靠数据库的锁机制完成,以确保操作最大程度的独占性。但随之
            而来的便是数据库 功用的很多开支,特别是对长事务而言,这样的开支往往无法接受。 如一个金融体系,当某个操作员读取用户的数据,并在读出的用户章鱼彩票app-Java进阶——亿级网站大数据量下的高并发同步解说数
            据的根底进步 行修正时(如更改用户帐户余额),假定选用失望锁机制,也就意味着整个操作过 程中(从操作员读出数据、开端修正直至提交修正成果的全
            进程,乃至还包含操作 员半途去煮咖啡的时刻),数据库记载一直处于加锁状况,能够想见,假定面临几 百上千个并发,这样的状况将导致怎样的成果。 乐
            观锁机制在必定程度上处理了这个问题。
            达观锁,大多是依据数据版别 Version )记载机制完成。何谓数据版别?即为数据添加一个版别标识,在依据数据库表的版别处理计划中,一般是通
            过为数据库表添加一个 “version” 字段来 完成。 读取出数据时,将此版别号一起读出,之后更新时,对此版别号加一。此刻,将提 交数据的版别数据与数据
            库表对应记载的当时版别信息进行比对,假定提交的数据 版别号大于数据库表当时版别号,则予以更新,不然认为是过期数据。 关于上面修正用户帐户信息
            的比方而言,假定数据库中帐户信息表中有一个 version 字段,当时值为 1 ;而当时帐户余额字段( balance )为 $100 。 操作员 A 此刻将其读出
            ( version=1 ),并从其帐户余额中扣除 $50( $100-$50 )。 2 在操作员 A 操作的进程中,操作员 B 也读入此用户信息( version=1 ),并 从其帐
            户余额中扣除 $20 ( $100-$20 )。 3 操作员 A 完结了修正工作,将数据版别号加一( version=2 ),连同帐户扣 除后余额( balance=$50 ),提交
            至数据库更新,此刻因为提交数据版别大 于数据库记载当时版别,数据被更新,数据库记载 version 更新为 2 。 4 操作员 B 完结了操作,也将版别号加一
            ( version=2 )企图向数据库提交数 据( balance=$80 ),但此刻比对数据库记载版别时发现,操作员 B 提交的 数据版别号为 2 ,数据库记载当时版
            本也为 2 ,不满足 “ 提交版别有必要大于记 录当时版别才干履行更新 “ 的达观锁战略,因而,操作员 B 的提交被驳回。 这样,就防止了操作员 B 用依据
            version=1 的旧数据修正的成果掩盖操作 员 A 的操作成果的或许。 从上面的比方能够看出,达观锁机制防止了长事务中的数据库加锁开支(操作员 A
            和操作员 B 操作进程中,都没有对数据库数据加锁),大大进步了大并发量下的系 统全体功用体现。 需求留意的是,达观锁机制往往依据体系中的数据存储
            逻辑,因而也具有必定的局 限性,如在上例中,因为达观锁机制是在咱们的体系中完成,来自外部体系的用户 余额更新操作不受咱们体系的操控,因而或许
            会形成脏数据被更新到数据库中。在 体系规划阶段,咱们应该充沛考虑到这些状况呈现的或许性,并进行相应调整(如 将达观锁战略在数据库存储进程中实
            现,对外只敞开依据此存储进程的数据更新途 径,而不是将数据库表直接对外揭露)。 Hibernate 在其数据拜访引擎中内置了达观锁完成。假定不必考虑外
            部体系对数 据库的更新操作,运用 Hibernate 供给的透明化达观锁完成,将大大进步咱们的 生产力。
            Hibernate 中能够经过 class 描述符的 optimistic-lock 特点结合 version描述符指定。
            现在,咱们为之前示例中的 User 加上达观锁机制。
            1 . 首要为 User 的POJO class
            package com.xiaohao.test;

            public class User {
            private Integer id;
            private String userName;
            private String password;
            private int version;

            public int getVersion() {
            return version;
            }
            public void setVersion(int version) {
            this.version = version;
            }
            public Integer getId() {
            return id;
            }
            public void setId(Integer id) {
            this.id = id;
            }
            public String getUserName() {
            return userName;
            }
            public void setUserName(String userName) {
            this.userName = userName;
            }
            public String getPassword() {
            return password;
            }
            public void setPassword(String password) {
            this.password = password;
            }
            public User() {}
            public User(String userName, String password) {
            super();
            this.userName = userName;
            this.password = password;
            }
            }
            然后是User.hbm.xml


            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
















            留意 version 节点有必要呈现在 ID 节点之后。
            这儿咱们声明晰一个 version 特点,用于寄存用户的版别信息,保存在 User 表的version中
            optimistic-lock 特点有如下可选取值:
            none
            无达观锁
            version
            经过版别机制完成达观锁
            dirty
            经过查看发作变动过的特点完成达观锁
            all
            经过查看一切特点完成达观锁
            其间经过 version 完成的达观锁机制是 Hibernate 官方引荐的达观锁完成,一起也
            是 Hibernate 中,现在仅有在数据方针脱离 Session 发作修正的状况下仍然有用的锁机
            制。因而,一般状况下,咱们都挑选 version 方法作为 Hibernate 达观锁完成机制。
            2 . 装备文件hibernate.cfg.xml和UserTest测验类
            hibernate.cfg.xml

            "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
            "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">



            org.hibernate.dialect.MySQL5InnoDBDialect

            update

            true

            false
            thread

            jdbc:mysql:///user
            root
            123456
            com.mysql.jdbc.Driver



            UserTest.java
            package com.xiaohao.test;
            import org.hibernate.Session;
            import org.hibernate.SessionFactory;
            import org.hibernate.Transaction;
            import org.hibernate.cfg.Configuration;

            public class UserTest {
            public static void main(String[] args) {
            Configuration conf=new Configuration().configure();
            SessionFactory sf=conf.buildSessionFactory();
            Session session=sf.getCurrentSession();
            Transaction tx=session.beginTransaction();
            // User user=new User("小浩","英豪");
            // session.save(user);
            // session.createSQLQuery("insert into user(userName,password) value('张英豪16','123')")
            // .executeUpdate();
            User user=(User) session.get(User.class, 1);
            user.setUserName("221");
            // session.save(user);

            System.out.println("祝贺您,用户的数据刺进成功了哦~~");
            tx.commit();
            }

            }
            每次对 TUser 进行更新的时分,咱们能够发现,数据库中的 version 都在递加。
            下面咱们即将经过达观锁来完成一下并发和同步的测验用例:
            这儿需求运用两个测验类,别离运行在不同的虚拟机上面,以此来模仿多个用户一起操作一张表,一起其间一个测验类需求模仿长事务
            UserTest.java
            package com.xiaohao.test;package com.xiaohao.test;留学生免税车

            import org.hibernate.Session;
            import org.hibernate.SessionFactory;
            import org.hibernate.Transaction;
            import org.hibernate.cfg.Configuration;

            public class UserTest {
            public static void main(String[] args) {
            Configuration conf=new Configuration().configure();
            SessionFactory sf=conf.buildSessionFactory();
            Session session=sf.openSession();
            // Session session2=sf.openSession();
            User user=(User) session.createQuery(" from User user where user=5").uniqueResult();
            // User user2=(User) session.createQuery(" from User user where user=5").uniqueResult();
            System.out.println(user.getVersion());
            // System.out.println(user2.getVersion());
            Transaction tx=session.beginTransaction();
            user.setUserName("101");
            tx.commit();

            System.out.println(user.getVersion());
            // System.out.println(user2.getVersion());
            // System.out.println(user.getVersion
            import org.hibernate.Session;
            import org.hibernate.SessionFactory;
            import org.hibernate.Transaction;
            import org.hibernate.cfg.Configuration;

            public class UserTest {
            public static void main(String[] args) {
            Configuration conf=new Configuration().configure();
            SessionFactory sf=conf.buildSessionFactory();
            Session session=sf.openSession();
            // Session session2=sf.openSession();
            User user=(User) session.createQuery(" from User user where user=5").uniqueResult();
            // User user2=(User) session.createQuery(" from User user where user=5").uniqueResult();
            System.out.println(user.getVersion());
            // System.out.println(user2.getVersion());
            Transaction tx=session.beginTransaction();
            user.setUserName("101");
            tx.commit();

            System.out.println(user.getVersion());
            // System.out.println(user2.getVersion());
            // System.out.println(user.getVersion()==user2.getVersion());
            // Transaction tx2=session2.beginTransaction();
            // user2.setUserName("4468");
            // tx2.commit();

            }

            }

             UserTest2.java

            package com.xiaohao.test;

            import org.hibernate.Session;
            import org.hibernate.SessionFactory;
            import org.hibernate.Transaction;
            import org.hibernate.cfg.Configuration;

            public class UserTest2 {
            public static void main(String[] args) throws InterruptedException {
            Configuration conf=new Configuration().configure();
            SessionFactory sf=conf.buildSessionFactory();
            Session session=sf.openSession();
            // Session session2=sf.openSession();
            User user=(User) session.createQuery(" from User user where user=5").uniqueResult();
            Thread.sleep(10000);
            // User user2=(User) session.createQuery(" from User user where user=5").uniqueResult();
            System.out.println(user.getVersion());
            // System.out.println(user2.getVersion());
            Transaction tx=session.beginTransaction();
            user.setUserName("100");
            tx.commit();

            System.out.println(user.getVersion());
            // System.out.println(user2.getVersion());
            // System.out.println(user.getVersion()==user2.getVersion());
            // Transaction tx2=session2.beginTransaction();
            // user2.setUserName("4468");
            // tx2.commit();

            }

            }

            操作流程及简略解说: 首要发动UserTest2.java测验类,在履行到Thread.sleep(10000);这条句子的时分,当时线程会进入睡觉状况。在10秒钟之内

            发动UserTest这个类,在抵达10秒的时分,咱们将会在UserTest.java中抛出下面的反常:

            Exception in thread "main" org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.xiaohao.tes章鱼彩票app-Java进阶——亿级网站大数据量下的高并发同步解说t.User#5]
            at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1932)
            at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2576)
            at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2476)
            at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2803)
            at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:113)
            at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
            at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
            at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:185)
            at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
            at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
            at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
            at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
            at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
            at com.xiaohao.test.UserTest2.main(UserTest2.java:21)

            UserTest2代码将在 tx.commit() 处抛出 StaleObjectStateException 异 常,并指出版别查看失利,当时事务正在企图提交一个过期数据。经过捕捉这个反常,我 们就能够在达观锁校验失利时进行相应处理

            3、常见并发同步事例剖析

            事例一:订票体系事例,某航班只要一张机票,假定有1w个人翻开你的网站来订票,问你怎么处理并发问题(可扩展到任何高并发网站要考虑的并发读写问题)

            问题,1w个人来拜访,票没出去前要确保咱们都能看到有票,不或许一个人在看到票的时别离人就不能看了。究竟谁能抢到,那得看这个人的“命运”(网络快慢等)

            其次考虑的问题,并发,1w个人一起点击购买,究竟谁能成交?一共只要一张票。

            首要咱们简略想到和并发相关的几个计划 :

            锁同步同步更多指的是运用程序的层面,多个线程进来,只能一个一个的拜访,java中指的是syncrinized关键字。锁也有2个层面,一个是java中谈到的对

            象锁,用于线程同步;别的一个层面是数据库的锁;假定是分布式的体系,明显只能运用数据库端的锁来完成。

            假定咱们选用了同步机制或许数据库物理锁机制,怎么确保1w个人还能一起看到有票,明显会献身功用,在高并发网站中是不可取的。运用hibernate后咱们

            提出了别的一个概念:达观锁失望锁(即传统的物理锁);

            选用达观锁即可处理此问题。达观锁意思是不确定表的状况下,运用事务的操控来处理并发问题,这样即确保数据的并发可读性又确保保存数据的排他性,保

            证功用的一起处理了并发带来的脏数据问题。

            hibernate中怎么完成达观锁:

            条件:在现有表傍边添加一个冗余字段,version版别号, long类型

            原理:

            1)只要当时版别号》=数据库表版别号,才干提交

            2)提交成功后,版别号version ++

            完成很简略:在ormapping添加一特点optimistic-lock="version"即可,以下是样例片段

            optimistic-lock="version" table="T_Stock" schema="STOCK">

            事例二、股票买卖体系、银行体系,大数据量你是怎么考虑的

            首要,股票买卖体系的行情表,每几秒钟就有一个行情记载发生,一天下来就有(假定行情3秒一个) 股票数量2060*6 条记载,一月下来这个表记载数

            量多大? oracle中一张表的记载数超越100w后 查询功用就很差了,怎么确保体系功用?

            再比方,中国移动有上亿的用户量,表怎么规划?把一切用于存在于一个表么?

            所以,大数量的体系,有必要考虑表拆分-(表姓名不相同,可是结构彻底相同),通用的几种方法:(视状况而定)

            1)按事务分,比方 手机号的表,咱们能够考虑 130最初的作为一个表,131最初的别的一张表 以此类推

            2)运用oracle的表拆分机制做分表

            3)假定是买卖体系,咱们能够考虑按时刻轴拆分,当日数据一个表,历史数据弄到其它表。这儿历史数据的报表和查询不会影响当日买卖。

            当然,表拆分后咱们的运用得做相应的适配。单纯的or-mapping或许就得改动了。比方部分事务得经过存储进程等

            此外,咱们还得考虑缓存

            这儿的缓存,指的不仅仅是hibernate,hibernate自身供给了一级二级缓存。这儿的缓存独立于运用,仍然是内存的读取,假定咱们能削减数据库频频的访

            问,那对体系必定大大有利的。比方一个电子商务体系的产品查找,假定某个关键字的产品经常被搜,那就能够考虑这部分产品列表寄存到缓存(内存中

            去),这样不必每次拜访数据库,功用大大添加。

            简略的缓存咱们能够了解为自己做一个hashmap,把常拜访的数据做一个key,value是第一次从数据库查找出来的值,下次拜访就能够从map里读取,而不

            读数据库;专业些的现在有独立的缓存结构比方memcached 等,可独立布置成一个缓存服务器。

            4、常见的进步高并发下拜访的功率的手法

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

            1、或许是服务器网络带宽不行

            2.或许web线程衔接数不行

            3.或许数据库衔接查询上不去。

            依据不同的状况,处理思路也不同。

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

            最终仿制一些在高并发下面需求常常需求处理的内容:

            • 尽量运用缓存,包含用户缓存,信息缓存等,多花点内存来做缓存,能够很多削减与数据库的交互,进步功用。
            • 用jprofiler等东西找出功用瓶颈,削减额定的开支。
            • 优化数据库查询句子,削减直接运用hibernate等东西的直接生成句子(仅耗时较长的查询做优化)。
            • 优化数据库结构,多做索引,进步查询功率。
            • 计算的功用尽量做缓存,或按每天一计算或守时计算相关报表,防止需求时进行计算的功用。
            • 能运用静态页面的当地尽量运用,削减容器的解析(尽量将动态内容生成静态html来显现)。
            • 处理以上问题后,运用服务器集群来处理单台的瓶颈问题。
            • Java进阶高并发面试材料后台私信我666即可获取。
            请关注微信公众号
            微信二维码
            不容错过
            Powered By Z-BlogPHP