java多线程使用心得

1.多线程的使用场景

其实简单归纳就是一点:想要提高响应速度就可以

举个很简单的业务,假使某个service里面涉及了4个mapper操作,且假使数据库部分耗时,每个mapper操作都约为1秒,普通的后台串行执行时间就是一个加法数学模型(1+1+1+1),这个时候若想提高效率最简单的方法就是同时执行这4个mapper操作,准确的描述是并发执行,这时若不考虑其他硬件性能,并发执行时间的数学模型大约为(1*N),这个N跟硬件性能、当前系统jvm之类的都有关,一般来说都是小于2的,这样一般情况下就能提高一倍的性能。

 

2.多线程常见的问题

 

1.主线程等待问题

主线程等待一个资源时不能一直等下去,需要设置一个最大值,要不会给用户一个很糟糕的体验,同时如果等待的人太多也会占有线程资源,影响性能。

举例:

Hystrix的服务降级,令牌桶、httpcliet的超时设置,阻塞队列的超时限制,java并发包的等待超时时间等待。。。一般来说都会设置一个最大值,防止这个队伍里的人一直无限延长。

 

2.数据共享问题

jmm相关,发生于多个线程共享一个变量且试图修改,造成一个线程修改另外线程无法读取到真实的值。

举例:

两个线程同时执行一段业务代码,传入一个boolean类型的变量,初始值为true,A线程发生异常,中断,将他们的boolean共享变量设置为false,B线程那边读到的永远都是ture。

最简单的办法就是使用final变量或Atomic变量,前者会禁止线程复制数据到自己内存里转为共享一个常量池,后者是原子类操作确保每次操作都会读取公告内存里的值。

 

3.子线程死锁问题

多线程环境下容易忽略一些细节导致某个线程一直执行或长时间占据线程资源,而系统内感知不到。

具体来说就是,假如调用一个业务接口的主线程超时了,主线程返回结果,主线程下面某个子线程没有被回收,而是继续执行,而一般场景下难以察觉到这个线程已经中断(所以有时候需要检测后台线程的功能),就会造成资源浪费,有的基于乐观锁机制的锁甚至还会发生死锁问题。

 

4.事务问题

子线程开启的事务不会合并到主线程事务里,并且和主线程所在的事务不是一个事务,每个线程都是一个独立的事务。

若有一个子线程发生了异常,只会他自己回滚。

实际中是,业务代码不能写到子线程的run内部,而是开启一个线程让其执行一个事务监控下的服务。

解决办法A:

需要设置一个共享值,所有线程执行业务时需要根据这个共享值判断是否有线程发生了异常,业务执行完后需要停下来等待其他线程执行完毕。

解决办法B:补偿机制,将发生异常的线程的数据保存起来发送给别的服务,在别的服务里进行补偿。

这两个办法有点像分布式事务里的内味了,强一致性和弱一致性。

 

5.子线程之间通信问题

和线程的数据共享有点像,这里主要说的是主线程如何控制多个不确定数量的子线程。

多线程等待多个线程执行完毕,同时多个线程之间也要等待主线程通知才能决定是否回滚。

涉及的有future队列,completeFutre,并发包等等。

举例A:

某个业务需要调取别的服务中4个不同的接口,这类情况下子线程之间没有关系。

举例B:

某个业务调用自己4个不通的接口,这4个接口都有事务相关性操作。这类情况下子线程之间有了关系,因为多线程下不确定谁先执行完,所以子线程之间需要等待彼此,主线程也要等待所有子线程执行完毕,java提供了计数器,屏蔽器等工具,可以确定一个值,子线程共享这个计数器,在finally里必定进行计数操作,然后被另外一个计数器屏蔽,主线程先被子线程计数器阻塞,被唤醒后再将主线程计数器减一,这样就达成了目的。

子线程:

主线程:

 

3.锁类型

大致分为没有锁的乐观锁和悲观锁,乐观锁简单来说是基于多个条件的循环,悲观锁有大量并发工具可以搭配使用。

若执行时间短,且竞争激烈可以采用乐观锁,若执行时间长,竞争不是太激烈可以用悲观锁。

不追求所谓的最优效率,其实两个锁都可以用,而且写法上使用悲观锁更易于阅读和控制。

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值