如何处理java高并发问题,第1张

如何处理并发和同步

今天讲的如何处理并发和同同步问题主要是通过锁机制。

我们需要明白,锁机制有两个层面。

一种是代码层次上的,如java中的同步锁,典型的就是同步关键字synchronized,这里我不在做过多的讲解,

感兴趣的可以参考:http://wwwcnblogscom/xiohao/p/4151408html

另外一种是数据库层次上的,比较典型的就是悲观锁和乐观锁。这里我们重点讲解的就是悲观锁(传统的物理锁)和乐观锁。

悲观锁(Pessimistic Locking):

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自 外部系统的事务处理)修改持保守态度,因此,

在整个数据处理过程中,将数据处于锁定状态。

悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能 真正保证数据访问的排他性,否则,即使在本系统

中实现了加锁机制,也无法保证外部系 统不会修改数据)。

一个典型的倚赖数据库的悲观锁调用:

select from account where name=”Erica” for update

这条 sql 语句锁定了 account 表中所有符合检索条件( name=”Erica” )的记录。

本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。

Hibernate 的悲观锁,也是基于数据库的锁机制实现。

下面的代码实现了对查询记录的加锁:

String hqlStr ="from TUser as user where username='Erica'";

Query query = sessioncreateQuery(hqlStr);

querysetLockMode("user",LockModeUPGRADE); // 加锁

List userList = querylist();// 执行查询,获取数据

querysetLockMode 对查询语句中,特定别名所对应的记录进行加锁(我们为 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 的加锁模式有:

Ø LockModeNONE : 无锁机制。

Ø LockModeWRITE : Hibernate 在 Insert 和 Update 记录的时候会自动获取

Ø LockModeREAD : Hibernate 在读取记录的时候会自动获取。

以上这三种锁机制一般由 Hibernate 内部使用,如 Hibernate 为了保证 Update

过程中对象不会被外界修改,会在 save 方法实现中自动为目标对象加上 WRITE 锁。

Ø LockModeUPGRADE :利用数据库的 for update 子句加锁。

Ø LockMode UPGRADE_NOWAIT : Oracle 的特定实现,利用 Oracle 的 for

update nowait 子句实现加锁。

上面这两种锁机制是我们在应用层较为常用的,加锁一般通过以下方法实现:

CriteriasetLockMode

QuerysetLockMode

Sessionlock

Java面试中常问关于多线程和高并发的问题,原因如下:

1 多线程和高并发是Java开发中常见的问题:Java是一种广泛应用于并发编程的语言,多线程和高并发是Java开发中常遇到的挑战。因此,面试官经常会问相关问题,以了解面试者对于这方面的理解和实践经验。

2 多线程和高并发涉及到核心的编程概念和技术:理解多线程和高并发需要掌握线程的基本概念、线程的生命周期、线程同步与互斥、锁机制、线程池等知识。这些是Java开发中非常重要的技术,对于能否编写高效、可靠的并发程序起着关键作用。

3 多线程和高并发是性能优化的重要方向:在现代应用程序开发中,高并发是一个常见的需求。通过合理地设计和优化多线程和并发,可以提高系统的性能和响应速度。因此,对于面试者来说,理解和掌握多线程和高并发的技术,对于解决性能问题和提升系统效率具有重要意义。

拓展内容:

除了上述原因外,多线程和高并发在现代的计算机系统中也具有重要的意义。随着计算机硬件的发展,多核处理器已经成为普遍存在的情况,而多线程的使用可以更好地利用多核处理器的优势,提高系统的并行处理能力。而高并发则是现代互联网应用中普遍存在的情况,如高并发的请求处理、数据库并发访问、分布式系统的并发操作等。因此,对于Java开发者来说,熟练掌握多线程和高并发编程技术,将有助于提高自己的竞争力和应对现实开发中的挑战。

public class Test {  

public static void main(String[] args) {  

int count = 1000;  

ExecutorService executorService = ExecutorsnewFixedThreadPool(count);  

for (int i = 0; i < count; i++)  

executorServiceexecute(new Test()new Task());  

executorServiceshutdown();  

while (!executorServiceisTerminated()) {  

try {  

Threadsleep(10);  

} catch (InterruptedException e) {  

eprintStackTrace();  

}  

}  

}  

public class Task implements Runnable {  

@Override  

public void run() {  

try {  

// 测试内容  

} catch (Exception e) {  

eprintStackTrace();  

}  

}  

}  

}  

如果要实现真正的并发同时执行,可通过CyclicBarrier来控制。

public class Test {  

public static void main(String[] args) {  

int count = 1000;  

CyclicBarrier cyclicBarrier = new CyclicBarrier(count);  

ExecutorService executorService = ExecutorsnewFixedThreadPool(count);  

for (int i = 0; i < count; i++)  

executorServiceexecute(new Test()new Task(cyclicBarrier));  

executorServiceshutdown();  

while (!executorServiceisTerminated()) {  

try {  

Threadsleep(10);  

} catch (InterruptedException e) {  

eprintStackTrace();  

}  

}  

}  

public class Task implements Runnable {  

private CyclicBarrier cyclicBarrier;  

public Task(CyclicBarrier cyclicBarrier) {  

thiscyclicBarrier = cyclicBarrier;  

}  

@Override  

public void run() {  

try {  

// 等待所有任务准备就绪  

cyclicBarrierawait();  

// 测试内容  

} catch (Exception e) {  

eprintStackTrace();  

}  

}  

}  

}  

不是很明白你问题的意思。

你说的“在服务端并发100个线程访问servlet的某一个接口,查询出100人的信息,然后打印出它们的id”,100个线程每个线程都查询100个人的信息?还是每个线程只查询一个人的信息,任意两个线程查询不同人的信息?

说实话 从软件或代码角度 没辙 都是长连接 逃不掉的

只能从系统设计上去考虑,大致上会有以下这两种思路(基本上是都用的):

1、对于所有的上传的文件,根据随机生成的名称或code取hash用策略取模,分服务器存/取文件,保证不触及io瓶颈,内部文件同步策略自己考虑

2、对所有请求,分pop点分发,根据用户的物理地址选择相应较近的pop点处理请求(当前pop请求已满则顺延至下一pop点,依次类推)

一、并发是一种需求,以下先介绍一下javaweb对于高并发的处理思路:

1、synchronized 关键字

可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。可能锁对象包括: this, 临界资源对象,Class 类对象

2、同步方法

同步方法锁定的是当前对象。当多线程通过同一个对象引用多次调用当前同步方法时, 需同步执行。

3、同步代码块

同步代码块的同步粒度更加细致,是商业开发中推荐的编程方式。可以定位到具体的同步位置,而不是简单的将方法整体实现同步逻辑。在效率上,相对更高。

A)锁定临界对象

同步代码块在执行时,是锁定 object 对象。当多个线程调用同一个方法时,锁定对象不变的情况下,需同步执行。

B)锁定当前对象

4、锁的底层实现

Java 虚拟机中的同步(Synchronization)基于进入和退出管程(Monitor)对象实现。同步方法 并不是由 monitor enter 和 monitor exit 指令来实现同步的,而是由方法调用指令读取运行时常量池中方法的 ACC_SYNCHRONIZED 标志来隐式实现的。

5、锁的种类

Java 中锁的种类大致分为偏向锁,自旋锁,轻量级锁,重量级锁。

锁的使用方式为:先提供偏向锁,如果不满足的时候,升级为轻量级锁,再不满足,升级为重量级锁。自旋锁是一个过渡的锁状态,不是一种实际的锁类型。

锁只能升级,不能降级。

6、volatile 关键字

变量的线程可见性。在 CPU 计算过程中,会将计算过程需要的数据加载到 CPU 计算缓存中,当 CPU 计算中断时,有可能刷新缓存,重新读取内存中的数据。在线程运行的过程中,如果某变量被其他线程修改,可能造成数据不一致的情况,从而导致结果错误。而 volatile 修饰的变量是线程可见的,当 JVM 解释 volatile 修饰的变量时,会通知 CPU,在计算过程中, 每次使用变量参与计算时,都会检查内存中的数据是否发生变化,而不是一直使用 CPU 缓存中的数据,可以保证计算结果的正确。

更多、此外还有很多细节需要通过学习去了解和完善,此处就不一一列举了。

二、并发框架

并发框架很多,如ExecutorService、RxJava、Disruptor、Akka等,具体选择哪个(或者都不选择)是根据项目需求选择的,框架本身的差异并不大,基本都是如下模式

DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
网站模板库 » 如何处理java高并发问题

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情