The content of this article is about how to solve high concurrency in Java? Java's high concurrency solution has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
For the website we develop, if the number of visits to the website is very large, then we need to consider related concurrent access issues. Concurrency issues are a headache for most programmers.
But then again, since we can’t escape it, let’s face it calmly~ Today let’s study the common ones Concurrency and synchronization.
In order to better understand concurrency and synchronization, we need to understand two important concepts first:Synchronization and asynchronous
1. The difference between synchronization and asynchronous And contact
The so-called synchronization can be understood as waiting for the system to return a value or message after executing a function or method. At this time, the program is blocked and only receives
Execute other commands only after returning the value or message.
Asynchronous, after executing the function or method, you do not have to wait blockingly for the return value or message. You only need to delegate an asynchronous process to the system. Then when the system receives the return value or message, the system will automatically trigger the delegation. an asynchronous process to complete a complete process.
Synchronization can be regarded as a single thread to a certain extent. After this thread requests a method, it will wait for the method to reply to it, otherwise it will not continue execution (dead-hearted).
Asynchronous can be regarded as multi-threaded to a certain extent (nonsense, how can a thread be called asynchronous). After requesting a method, it will be ignored and continue to execute other methods.
Synchronization is one thing, done one thing at a time.
Asynchronous means doing one thing without causing other things to be done.
For example:
Eating and talking can only happen one at a time, because there is only one mouth. But eating and listening to music are asynchronous, because listening to music does not cause us to eat.
For Java programmers, we will often hear the synchronization keyword synchronized. If the synchronization monitoring object is a class, then if an object accesses the synchronization method in the class, then other objects If you want to continue to access the synchronization method in the class, it will enter blocking. Only after the previous object has finished executing the synchronization method can the current object continue to execute the method. This is synchronization. On the contrary, if there is no synchronization keyword modification before the method, then different objects can access the same method at the same time, which is asynchronous.
To add (related concepts of dirty data and non-repeatable reading):
Dirty data
Dirty reading means that when a transaction is accessing data, and the data is The modification has not yet been committed to the database. At this time, another transaction also accesses the data and then uses the data. Because this data has not yet been committed, the data read by another transaction is dirty data, and operations based on dirty data may be incorrect.
Non-repeatable reading
Non-repeatable reading refers to reading the same data multiple times within a transaction. Before this transaction ends, another transaction also accesses the same data. Then, between the two reads of data in the first transaction, due to the modification of the second transaction, the data read twice by the first transaction may be different. In this way, the data read twice in one transaction is different, so it is called non-repeatable read
2. How to deal with concurrency and synchronization
Today’s talk How to deal with concurrency and synchronization issues is mainly through the lock mechanism.
We need to understand that the locking mechanism has two levels.
One is at the code level, such as the synchronization lock in Java. The typical synchronization keyword is synchronized. I will not explain too much here.
The other is at the database level. Above, the more typical ones are pessimistic locking and optimistic locking. What we focus on here is pessimistic locking (traditional physical locking) and optimistic locking.
Pessimistic Locking:
Pessimistic locking, as its name suggests, refers to the processing of data that is blocked by the outside world (including other current transactions of this system and transactions from external systems) ) modification, therefore, the data is locked during the entire data processing process.
The implementation of pessimistic locking often relies on the locking mechanism provided by the database (only the locking mechanism provided by the database layer can truly guarantee the exclusivity of data access. Otherwise, even if the locking mechanism is implemented in this system, it cannot Ensure that external systems will not modify the data).
A typical pessimistic lock call that relies on the database:
select * from account where name=”Erica” for update
This sql statement locks all records in the account table that meet the retrieval conditions (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_NOWAIT : 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):
相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依 靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库 性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。 如一个金融系统,当某个操作员读取用户的数据,并在读出的用户数据的基础上进 行修改时(如更改用户帐户余额),如果采用悲观锁机制,也就意味着整个操作过 程中(从操作员读出数据、开始修改直至提交修改结果的全过程,甚至还包括操作 员中途去煮咖啡的时间),数据库记录始终处于加锁状态,可以想见,如果面对几 百上千个并发,这样的情况将导致怎样的后果。 乐观锁机制在一定程度上解决了这个问题。
乐观锁,大多是基于数据版本 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 提供的透明化乐观锁实现,将大大提升我们的 生产力。
User.hbm.xml
注意 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
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; 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.test.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. Analysis of common concurrent synchronization cases
Case 1: Booking system case, there is only one ticket for a certain flight, assuming that 10,000 people open your website to book tickets, ask How do you solve the concurrency problem (can be extended to any concurrent reading and writing issues that need to be considered on any high-concurrency website)
problem, 10,000 people come to visit, before the ticket is issued, you must ensure that everyone can see that there is a ticket, it is impossible When one person sees the ticket, others cannot see it. Who can grab it depends on the person's "luck" (network speed, etc.). The second consideration is concurrency. If 10,000 people click to buy at the same time, who can make the deal? There is only one ticket in total.
First of all, we can easily think of several solutions related to concurrency:
Lock synchronization Synchronization refers more to the application level. Multiple threads come in and can only be accessed one by one. Java The middle finger refers to the syncrinized keyword. Locks also have two levels, one is the object lock mentioned in Java, which is used for thread synchronization; the other level is the database lock; if it is a distributed system, obviously it can only be achieved by using the lock on the database side.
Assuming that we use a synchronization mechanism or a database physical lock mechanism, how to ensure that 10,000 people can still see the tickets at the same time will obviously sacrifice performance, which is not advisable in high-concurrency websites. After using hibernate, we came up with another concept: optimistic locking and pessimistic locking (i.e. traditional physical lock); using optimistic locking can solve this problem. Optimistic locking means using business control to solve concurrency problems without locking the table. This ensures the concurrent readability of data and the exclusivity of saved data. It ensures performance while solving the problem of dirty data caused by concurrency.
How to implement optimistic locking in hibernate:
Premise: Add a redundant field to the existing table, version version number, long type
Principle:
1) Only the current version number = database table version number can be submitted
2) After successful submission, the version number version
The implementation is very simple: add an attribute optimistic-lock to ormapping ="version" is enough. The following is a sample snippet
Case 2, stock trading system, banking system, how do you consider the amount of large data
First, the market situation of the stock trading system In the table, a market record is generated every few seconds, and there will be one in a day (assuming one market every 3 seconds). The number of stocks × 20 × 60 * 6 records. How many records will there be in this table in one month? When the number of records in a table in Oracle exceeds 1 million, query performance becomes very poor. How to ensure system performance?
For another example, China Mobile has hundreds of millions of users. How to design the table? Put everything in one table? Therefore, for a large number of systems, table splitting must be considered - (the table names are different, but the structures are exactly the same). There are several common methods: (depending on the situation)
1) Divide by business, such as For the table of mobile phone numbers, we can consider the one starting with 130 as one table, the other table starting with 131, and so on
2) Use Oracle's table splitting mechanism to create separate tables
3 ) If it is a trading system, we can consider splitting it according to the timeline, with the current day's data in one table and the historical data in another table. The reports and queries of historical data here will not affect the trading of the day.
Of course, after the table is split, our application must be adapted accordingly. Simple or-mapping may have to be changed. For example, some businesses have to go through stored procedures, etc.
In addition, we have to consider caching
The cache here refers not only to hibernate, but hibernate itself provides first- and second-level cache. The cache here is independent of the application and is still a memory read. If we can reduce the frequent access to the database, it will definitely be of great benefit to the system. For example, in an e-commerce system's product search, if a product with a certain keyword is frequently searched, then you can consider storing this part of the product list in the cache (in memory), so that you do not need to access the database every time, and the performance is greatly improved.
Simple caching can be understood as making a hashmap for yourself, and making a key for frequently accessed data. The value is the value searched from the database for the first time. You can read it from the map the next time you visit. Instead of reading the database; more professional ones currently have independent caching frameworks such as memcached, which can be independently deployed as a cache server.
4. Common methods to improve the efficiency of high concurrency access
First of all, we must understand where the bottleneck of high concurrency is?
1. Maybe the server network bandwidth is not enough
2. Maybe there are not enough web thread connections
3. Maybe the database connection query cannot be accessed.
According to different situations, the solution ideas are also different.
Like the first case, network bandwidth can be increased and DNS domain name resolution is distributed to multiple servers.
Load balancing, front-end proxy server nginx, apache, etc.
Database query optimization, read-write separation, table partitioning, etc.
Finally copy some that are needed under high concurrency Content that often needs to be processed:
Try to use cache, including user cache, information cache, etc. Spending more memory for caching can greatly reduce the interaction with the database and improve performance.
Use tools such as jprofiler to find performance bottlenecks and reduce additional overhead.
Optimize database query statements and reduce the number of directly generated statements using hibernate and other tools (only long-term queries are optimized).
Optimize the database structure, create more indexes, and improve query efficiency.
The statistics function should be cached as much as possible, or statistics should be collected once a day or at regular intervals to avoid statistics when needed.
Use static pages wherever possible to reduce container parsing (try to generate static html for dynamic content for display).
After solving the above problems, use a server cluster to solve the bottleneck problem of a single server.
Java has high concurrency, how to solve it, how to solve it
Before I mistakenly thought that the solution to high concurrency could be solved by threads or queues, because high concurrency Sometimes there are many users accessing, resulting in incorrect system data and data loss, so I thought Queues are used to solve the problem. In fact, queues can also be used. For example, when we are bidding on products, forwarding comments on Weibo, or selling flash sales of products, the number of visits at the same time is particularly large. Queues play a special role here. All requests are put into the queue and processed in an orderly manner in milliseconds, so that there will be no data loss or incorrect system data.
After checking the information today, I found that there are two solutions to high concurrency:
One is to use caching, the other is to use static pages; the other is to start from the most basic place Optimize the code we write to reduce unnecessary waste of resources: (
1. Do not use new objects frequently. Use singleton mode for classes that only need one instance in the entire application. For String connection operations, use StringBuffer or StringBuilder. For utility type classes, access them through static methods.
2. Avoid using wrong methods. For example, Exception can control the method launch, but Exception should retain stacktrace to consume performance. Do not use it unless necessary. For instanceof to make conditional judgment, try to use the conditional judgment method of ratio. Use efficient classes in JAVA, such as ArrayList, which has better performance than Vector. )
First of all, I have never used caching technology. I think it should save the data in the cache when the user requests it. The next request will detect whether there is data in the cache to prevent multiple requests to the server. It will cause the server performance to decrease and seriously cause the server to crash. This is just my own understanding. Detailed information still needs to be collected online. I think you should not use the method to generate static pages. We have seen many websites when the page is requested. Most have changed, such as "http://developer.51cto.com/art/201207/348766.htm". This page is actually a server request address. After being converted into HTM, the access speed will increase because static pages do not have There are server components; I will introduce them more here:
1. What is page staticization:
Brief Simply put, if we visit a link ,The corresponding module of the server will process this request, go to the corresponding jsp interface, and finally generate the data we want to see. The disadvantage of this is obvious: because every request to the server will be processed, such as If there are too many high concurrent requests, it will increase the pressure on the application server, and may even bring the server down. So how to avoid it? If we put the pair test.do The result after the request is saved into an html file, and then the user accesses it every time. Wouldn't the pressure on the application server be reduced?
So where do static pages come from? We can’t let us process each page manually, right? This involves what we are going to explain, the static page generation solution... What we need is to automatically generate a static page. When a user visits, test.html will be automatically generated and then displayed to the user.
2. Let’s briefly introduce the knowledge points that you should master if you want to master the page staticization scheme:
1. Basics - URL Rewrite
What is URL Rewrite? ? URL rewriting. Let’s use a simple example to illustrate the problem: enter the URL, but actually access abc.com/test.action, then we can say that the URL has been rewritten. This technology is widely used and there are many open source tools that can achieve this function.
2. Basics - Servlet web.xml
If you still don’t know how a request and a servlet are matched together in web.xml, then please search the servlet documentation. This is not nonsense, many people think that the matching method /xyz/*.do can be effective.
If you still don’t know how to write a servlet, then please search for how to write a servlet. This is no joke. Today, with various integration tools flying around, many people will not write a servlet from scratch. servlet.
3. Basic solution introduction
Among them, for the URL Rewriter part, you can use paid or open source tools to implement it. , if the URL is not particularly complex, you can consider implementing it in a servlet, then it will look like this:
总 结:其实我们在开发中都很少考虑这种问题,直接都是先将功能实现,当一个程序员在干到1到2年,就会感觉光实现功能不是最主要的,安全性能、质量等等才是 一个开发人员最该关心的。今天我所说的是高并发。
我的解决思路是:
1、采用分布式应用设计
2、分布式缓存数据库
3、代码优化
Java高并发的例子:
具体情况是这样: 通过java和数据库,自己实现序列自动增长。
实现代码大致如下:
id_table表结构, 主要字段:
id_name varchar2(16); id_val number(16,0); id_prefix varchar2(4);
//操作DB public synchronized String nextStringValue(String id){ SqlSession sqlSess = SqlSessionUtil.getSqlSession(); sqlSess.update("update id_table set id_val = id_val + 1 where id_name="+id); Map map = sqlSess.getOne("select id_name, id_prefix, id_val from id_table where id_name="+ id); BigDecimal val = (BigDecimal) map.get("id_val"); //id_val是具体数字,rePack主要是统一返回固定长度的字符串;如:Y0000001, F0000001, T0000001等 String idValue = rePack(val, map); return idValue; } //公共方法 public class IdHelpTool{ public static String getNextStringValue(String idName){ return getXX().nextStringValue(idName); } }
具体使用者,都是通过类似这种方式:IdHelpTool.getNextStringValue("PAY_LOG");来调用。
问题:
(1) 当出现并发时, 有时会获取重复的ID;
(2) 由于服务器做了相关一些设置,有时调用这个方法,好像还会导致超时。
为了解决问题(1), 考虑过在方法getNextStringValue上,也加上synchronized , 同步关键字过多,会不会更导致超时?
跪求大侠提供个解决问题的大概思路!!!
解决思路一:
1、推荐 https://github.com/adyliu/idcenter
2、可以通过第三方redis来实现。
解决思路一:
1、出现重复ID,是因为脏读了,并发的时候不加 synchronized 比如会出现问题
2、但是加了 synchronized ,性能急剧下降了,本身 java 就是多线程的,你把它单线程使用,不是明智的选择,同时,如果分布式部署的时候,加了 synchronized 也无法控制并发
3、调用这个方法,出现超时的情况,说明你的并发已经超过了数据库所能处理的极限,数据库无限等待导致超时
基于上面的分析,建议采用线程池的方案,支付宝的单号就是用的线程池的方案进行的。
数据库 update 不是一次加1,而是一次加几百甚至上千,然后取到的这 1000个序号,放在线程池里慢慢分配即可,能应付任意大的并发,同时保证数据库没任何压力。
The above is the detailed content of How to solve high concurrency in Java? Java high concurrency solution. For more information, please follow other related articles on the PHP Chinese website!