这一章讲的是多线程。我们的开发中用到多线程的地方比较少,主要的原因都是没必要,使用多线程带来的风险远比提高的速度多。
这节介绍了如何分析使用多线程的场景。这个地方讲的内容我们肯定是用不到的,场景不一样,不过它讲的内容倒很值得我们学习。
先说一下场景的区别,我们的系统里用到多线程的场景是:同一个Task需要循环执行多次。书里介绍的场景是不同Task之间的并行执行。
单一Task使用并发的判断依据
对于我们的这种场景,需不需要使用我觉得可以有几个角度去看:
-
单个Task的执行速度
这个我是放在第一位的,如果单个Task执行时间只有几十几百毫秒,串行循环执行几千几万次也是可以接受的。这个时候如果使用多线程,系统调度的花销会比较大。
有一个例子,之前的一个报表,需要对几百组单子进行统计分析,一组单子的处理时间在几分种左右,这个情形就可以使用多线程了。我们就是使用了Java8的parallelStream,速度提升了不少
-
共享资源
共享资源的竞争结果,基本也是将并发变成了串行。在设计多线程场景之前,要先想清楚线程之间的资源是不是完全独立的,如果出现了共享资源,就需要三思了
-
数据库锁
这个和之前一点是一样的,共享资源可以说是内存中的共享资源,这里说的是站在持久层的角度看共享资源。之前发生过的例子,我们的Domain结构中,Tariff是从属于Contract的,Tariff的version改变也会使Contract的version改变。我们有两个节点可以处理Q中的消息,这个消息是用来更新Tariff的信息的,这就导致了很严重的并发问题,如果两个节点同时更新了同一个Contract下的Tariff,就会造成乐观锁,从结果来看60%多的消息因为乐观锁而失败。最后还是使用了别的方法去掉了并发。�
此外,并发带来的另外一个副作用是很难追查问题,之前在看代码的时候发现了很多并发问题的隐患,如果发生了产品Exception也很难追查当时的状态
public class Service {
private static String a;
public static processString(String b) {
if (!b.equals(a)) {
a = b;
}
... others
}
}
@Service
public class ServiceB {
private String a;
public void processString(String a) {
this.a = a;
}
}
这两个情况也都比较简单,写代码的人也不是故意的,有时候是一不小心引入的问题,但总是难免会犯错,真的防止这种事情可能需要加一些Check Style机制?
网友评论