java中的并发,java并发三大特性,Java 实现并发的几种方式小结

java中的并发,java并发三大特性,Java 实现并发的几种方式小结

这篇文章主要介绍了Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)实现并发的几种方式小结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Java实现并发的几种方法

Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)程序默认以单线程方式运行。

synchronized

Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)用过同步的关键字来保证一次只有一个线程在执行代码块。

公共同步空的代码(){

//TODO

}

Volatile

不稳定的关键字保证任何线程在读取不稳定的修饰的变量的时候,读取的都是这个变量的最新数据。

Threads 和 Runnable

公共类MyRunnable实现可运行{

@覆盖

公共无效运行(){

//TODO

}

}

导入Java。util。ArrayList

导入Java。util。列表;

公共类主要{

公共静态void main(String[] args) {

runnable task=new my runnable();

线程工作者=新线程(任务);

工人。集合名称(' my runnable ');

工人。start();

}

创建线会有很多开销,性能低且不易管理

Thread pools

导入Java。util。并发。执行服务;

导入Java。util。并发。遗嘱执行人;

公共类主要{

private static final int NUMOFTHREDS=5;

公共静态void main(String[] args) {

执行者服务执行者=执行者。newfixedthreadpool(NUMOFTHREDS);

for(int I=0;i 50i ) {

runnable worker=new my runnable(I);

执行者.执行(工人);

}

//执行者不接受新的线

executor.shutdown().

//等待所有线结束

执行人。wait termination();

System.out.println('完成所有线程');

}

}

Futures 和 Callables

因为可追捕的对象无法向调用者返回结果,我们可以用请求即付的类来返回结果。

包de。我是盖勒。并发性。可赎回;

导入Java。util。并发。可赎回;

公共类MyCallable实现CallableLong {

@覆盖

公共长调用()引发异常{

//TODO

int sum=1;

返回总和;

}

}

导入Java。util。ArrayList

导入Java。util。列表;

导入Java。util。并发。可赎回;

导入Java。util。并发。执行异常;

导入Java。util。并发。执行服务;

导入Java。util。并发。遗嘱执行人;

导入Java。util。并发。未来;

公共类可赎回期货

private static final int NUMOFTHREDS=5;

公共静态void main(String[] args) {

执行者服务执行者=执行者。newfixedthreadpool(NUMOFTHREDS);

ListFutureLong list=new ArrayListFutureLong();

for(int I=0;i 10i ) {

callable long worker=new my callable();

未来长提交=执行者。提交(工人);

list.add(提交);

}

long sum=0;

for (FutureLong future : list) {

尝试{

总和=未来。get();

} catch (InterruptedException e) {

e。printstacktrace();

} catch (ExecutionException e) {

e。printstacktrace();

}

}

系统。出去。println(sum);

executor.shutdown().

}

}

CompletableFuture

可完成的未来在将来的的基础上增加了异步调用的功能回调()函数线执行结束的时候会自动调用。

可完成的未来既支持阻塞,也支持非阻塞的回调()

导入Java。util。并发。completablefuture

导入Java。util。并发。执行异常;

公共类CompletableFutureSimpleSnippet {

公共静态void main(String[] args) {

CompletableFutureInteger data=createCompletableFuture()。然后应用((整数计数)- {

int transformedValue=count * 10

返回转换后的值;

});

尝试{

int count=未来计数。get();

} catch(中断异常|执行异常ex){

}

}

私有静态CompletableFutureInteger createCompletableFuture(){

CompletableFutureInteger future count=completablefuture . supply async(

() - {

返回1;

});

返回futureCount

}

}

补充:Java如何处理高并发的情况

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

同步可以理解为在执行一个函数或方法后,等待系统的返回值或消息。此时程序被阻塞,只在收到返回值或消息后执行其他命令。同步意味着一次做一件事。

异步,在执行一个函数或方法后,你不必以一种阻碍的方式等待返回值或消息,而只需要委托一个异步进程给系统。然后,当系统收到返回值或消息时,系统会自动触发委托异步流程,从而完成一个完整的流程。异步是指做一件事不影响做其他事。

关键词synchronized,如果本次同步的被监控对象是一个类,那么如果一个对象访问了该类中的同步方法,其他对象要继续访问该类中的同步方法就会被阻塞,当前对象只有在前一个对象执行完同步方法后才能继续执行方法。这就是同步。相反,如果方法前没有同步关键字修饰,那么不同的对象可以同时访问同一个方法,这就是异步。

脏数据:是指当一个事务正在访问数据并修改数据,但修改还没有提交到数据库时,另一个事务也访问了数据,然后使用了数据。因为这个数据是未提交的数据,所以另一个事务读取的数据是脏数据,基于脏数据的操作可能是不正确的。

1、什么是并发问题

多个进程或线程同时(在同一时间段内)访问同一资源会导致并发问题。

比如,A操作员和B操作员同时读取一个余额为1000元的账户,A操作员在账户上加100元,B操作员从账户上减去50元,A操作员先提交,B操作员再提交。实际账户余额是1000-50=950元,其实应该是1000-100-50=1050。这是一个典型的并发问题。怎么解决?

并发和同步主要由锁定机制处理。

2、如何处理并发和同步

一个是java中的同步锁,典型的就是synchronized关键字。

另一个典型的是悲观锁和乐观锁。

在java中有两种方式实现原子性操作(即同步操作):

1)使用同步关键字synchronized。

2)使用锁机制,也包括相应的读写锁。

悲观锁,顾名思义,是指对外界对数据的修改(包括本系统当前的其他事务,以及来自外部系统的事务)保持保守的态度。因此,在整个数据处理过程中,数据是被锁定的。

乐观锁定,多基于数据版本Version)记录机制。什么是数据版本?也就是说,向数据添加版本标识符。在基于数据库表的版本解决方案中,一般通过在数据库表中增加一个“版本”字段来实现。在读取数据的时候,一起读取这个版本号,然后在更新的时候在这个版本号上加一。此时,将提交数据的版本数据与记录在数据库表中的当前版本信息进行比较。如果提交数据的版本号大于数据库表的当前版本号,则更新;否则,将被视为过期数据。

我们的系统实现了乐观锁机制,来自外部系统的用户余额更新操作不受我们的系统控制,因此可能会导致脏数据更新到数据库中。在系统设计阶段,要充分考虑这些情况的可能性,并做出相应的调整(比如在数据库存储过程中实施“快乐视图锁”的策略,只对外界开放基于这个存储过程的数据更新路径,而不是直接公开数据库表)。

【当心面试官会在这里问关于死锁的问题!死锁问题在其他一些博客中有解释]

3、常见并发同步案例分析

案例一、订票系统案例

一个航班只有一张票。假设1w人打开你的网站订票,问你如何解决并发问题(可以推广到任何高并发网站都要考虑的并发读写问题)。

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

乐观锁定可以解决这个问题。乐观锁是指在不锁表的情况下使用业务控制解决并发问题,既保证了数据的并发可读性又保证了存储数据的排他性,从而保证了性能,解决了并发带来的脏数据问题。

如何实现乐观锁定:

前提:在现有表中添加一个冗余字段,版本号和长类型。

原则:

1)只能提交当前版本号=数据库表版本号。

2)提交成功后,版本号版本

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

首先,股票交易系统的报价表每隔几秒钟就有一次报价记录。一天下来,有(假设报价3秒)6个股票数量 20 60 *的记录。这张表一月份的记录数是多少?当一个表中的记录数超过100w时,查询性能会很差。如何保证系统性能?

比如中国移动有几亿用户。桌子怎么设计?对一个表中的现有内容使用all?

因此,对于大量系统,必须考虑表拆分——(表名不同,但结构完全相同)。常见的有几种方式:(视情况而定)

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

2)使用分表机制分表。

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

此外,我们还必须考虑缓存。

这里的缓存独立于应用程序,仍然读取内存。如果能减少对数据库的频繁访问,肯定对系统有很大的好处。比如在一个电子商务系统的商品搜索中,如果某个关键词的商品被频繁搜索,可以考虑将这部分商品列表存储在缓存(内存)中,这样不用每次都访问数据库,性能大大提升。

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

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

1.服务器网络的带宽可能不足。

2.可能没有足够的web线程连接。

3.可能数据库连接查询不起来。

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

1.和第一种情况一样,可以增加网络带宽,DNS域名解析分布到多台服务器。

2.负载均衡,预代理服务器nginx,apache等。

3.数据库查询优化,读写分离,表拆分等。

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

1.尽量使用缓存,包括用户缓存、信息缓存等。并将更多的内存用于缓存,这样可以大大减少与数据库的交互,提高性能。

2.使用jprofiler等工具找出性能瓶颈,减少额外开销。

3.优化数据库查询语句,使用hibernate等工具减少直接生成语句(只优化耗时较长的查询)。

4.优化数据库结构,多做索引,提高查询效率。

5.统计的功能尽量缓存,或者按日或定时统计相关报表,避免需要时统计的功能。

6.尽可能使用静态页面,减少对容器的解析(尽量生成静态html以显示动态内容)。

7.解决以上问题后,用服务器集群解决单机瓶颈问题。

以上个人经历,希望能给大家一个参考,也希望大家多多支持我们。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: