今天看到的一个java多线程问题

尝试解决了一下,并且尝试延伸。

 

一、问题情景

现有数据库mysql,一数据表名为user,字段为主键id、username、password,需要向数据库中输入10000条记录。

二、初步解决

当时我一看就觉得这问题真简单,只要写个list直接插入不就好了吗。

后来想想,10000条记录是不是有点多,干脆开10条线程分别插入,最多需要注意下线程安全:

这里为了线程安全,使用了AtomicInteger这个类。否则就需要使用synchronized关键字,修饰getincrementId方法:

相对的,如果要让incrementId自增,不能直接incrementId++,要使用incrementAndGet。

三、注意这个表是user

问题情境中有表结构的信息,唯独没有提到要插入的数据。既然是user表,那么username一般是不可重复的,但是我们怎么确保要输入的数据中没有相同的username呢?

(1)设置数据库唯一索引,强行插入

既然没有提到不能修改表段,那么干脆给username设置一个唯一索引,然后代码照常即可。如果有username重复的情况出现,默认会插入第一个username信息,其他的重复的username继续插入就会报错。

问题是:如果报错了,我确实知道有插入错误,但是哪个数据插入失败了(即username重复了)我就不清楚了。

(2)插入前先对所有的数据做一次校验,检测同名情况

假设数据是json,那么大概可以这样检测同名情况:

pojo.java

testSameName.java

然后直接插入即可。

注意这里因为数据量不多(再怎么样都不会超过10000),所以能全部加载到内存中进行检测。如果数据量大,肯定是会出问题的。这时候就需要分割整个list,在多个线程中进行去重,最后合并结果。

其实只要数据量多起来了,事情就会变得很麻烦。可以参考:

http://blog.csdn.net/zyq522376829/article/details/47686867

四、注意id这个字段

本问题说明了数据库为mysql(不然没法指定数据库驱动),但是没有说明id字段的信息,一般这种情况id都是int,然后允许自增。干脆考虑极端一点,万一表中已经有数据了怎么办?万一id需要是uuid怎么办?万一id是int,但是不允许开启自增怎么办?

(1)生成uuid

可以在数据库中自动生成:

mybatis 随机id(含oracle和mysql)

也可以在java中生成:

(2)id是int,但是不允许开启自增/数据库中已经存在数据

关于这个问题我没有比较好的解决办法,只能想办法获取数据库中最大的id,然后依次+1,这样就不会重复。

获取最大的id:

获取最大id的数据:

五、总结

这个问题的难点主要是在多线程。这里有一些常见问题:

一个很大的文件保存着很多字符串(内存一次肯定装不下),要怎么将其去重并且汇总?

一个很大的文件记录着交易信息,要怎么把所有订单的金额计算出来?(涉及到怎么去通过关键字取到金额并且将其分开统计,最后汇总)。

这些问题都有一系列明显的特点(文件大,内存装不下、提取数据、分别计算、最后汇总),所以也有一系列的解决方法,同时引出更多的问题:文件大那就分文件加载(涉及到一个分多大,分多少的问题)。分文件处理慢就要开多线程来提高效率(怎么保证多线程中的数据的线程安全)。提取数据(如何进行提取?怎么提取效率高)这个我还没试过,应该不是很难。分别计算(涉及到线程之间互不干涉的问题)和汇总(保证主线程在所有子线程执行之后才执行)其实也不是很难。

多线程好解决,关键是各种实现细节。既要做到速度快,也要做到线程安全,不是一件容易的事情。下次自己制造一个需求来练练。

发表评论

电子邮件地址不会被公开。 必填项已用*标注