大家一起来探讨一下一个多线程任务的设计吧,希望高手进来指教

时间:2021-12-19 16:55:44
假设有N条记录要从数据库中读出,然后导成文件

我是想到了以下两个方法,但也有些疑问
一、固定的5个线程,每个线程处理100条记录

    问题是:当这5个线程处理外500条记录后,怎么办?全部WAIT()在那边,然后当新的500条记录分配下来后一个个NOTIFY,那这5个线程如何让其再次运行?

           重新NEW出来5个线程,那这样JVM不是来不及释放


二、线程池,线程池和JDBC连接池一样,开5个线程,然后每个线程处理100条记录,把N条记录一起扔给这个线程池,此线程池固定处理是500条记录,其他记录排队?

   问题是: 排队?排在那边,也是排在内存中啊?那我有100万条记录,就是有100万-500条记录记录排在内存中啊?我用多线程处理就是希望想分批读出记录做处理,

           这样一来不是起不到效果了?

请大家参与讨论

23 个解决方案

#1


线程池肯定要更好一些啊.
不一定要销毁线程啊,可以让它们Sleep直到有新的任务在唤醒它们啊.

#2


引用 1 楼 yeah920 的回复:
帮忙顶一下,让了解的人来解答.


按照您的意思就是,有任务来了就唤醒,是不就是说,如果我这个是一个导出数据成文件的程序,那这个进程的生命是随着我整个程序的开始而开始,结束而结束?

还有,您指的让它一直SLEEP是指WAIT()还是SLEEP(),如果是SLEEP(),如何弄醒它?

#3


帮顶

#4


帮顶一个 
期待着高手的到来

#5


不懂 楼主的意思 帮顶一下吧  

#6


用多线程,connection 池

#7


不是很清楚,但你可以将它放入一个时间里,当执行500后将时间停止,当再用时将时间打开即可

#8


没看明白,既然楼主有100万条记录,为什么处理完500条就让所有线程都歇着?

#9


引用 9 楼 ZXEOC 的回复:
没看明白,既然楼主有100万条记录,为什么处理完500条就让所有线程都歇着?


同问,本来使用线程就是想通过并行来提高效率,既然需要处理这么多的数据量为什么要分批次呢?
另外,关于数据库访问的貌似都是用连接池来处理的

#10


逻辑还是和数据库链接的使用一样的,要用生成,用完杀掉.......

一个处理类,继承自线程,里面有一个属性保存要处理的记录
启动后就运行你的记录处理逻辑,只处理获得的记录,处理完就完了,这个线程自动就会消失

一个主类,取记录,取够你想拆分的数量(100条)后,
就new一个处理类,把这100条记录传给他,让他start去处理
再取100条记录,再new一个处理类,再start

逻辑就应该是这样,至于说频繁生成线程销毁线程的开销,可以通过调节你的拆分数量来控制
另外,线程池也是为了优化这点而生的
但并不是说要保持住多少个线程让他wait在那里来处理,这不是一个好的业务逻辑

#11


另外,你还要一个逻辑上的错误

既然你有100W条记录,分5个线程,为什么是每个线程分配100条,然后等这些线程处理完100条了再分100条?
直接每个线程分配100W/5条就可以了啊,

至于你说的有100W条在内存
记录在不在内存,取决你什么时候取出来,而不是取决于你什么时候去处理

如果你不想占内存,你就每次取少部分取来处理,就像分页一样

#12


可以考虑先把数据存入队列,N条数据来的时候就先把数据原模原样的存入数据库,然后可以建立一个创建定时器,在定制任务,比如每个10秒 处理100条数据。
比如
cycletime=10000;
//创建定时器
Sender.timer = new Timer(true);
//定制任务
Sender.timer.schedule(new TimerTask() {
     public void run() {
new  SenderThread().start();
}
}, 0, cycletime);
红色部分就是每个多少时间生成一个新的发送数据的线程,每次从队列数据库中取出100条数据进行处理,当然数据从队列出来的时候是要考虑线程安全的。

#13


楼主好人我来绑定!!!

#14


占个位子,关注。

#15


关注。

#16


我再添一把油,我现在想到这样的设计:

还是5个线程,每个处理100条,一共假设有100万条记录

这5个线程处理完了500条数据后,自动销毁!

然后外层一个循环,再创建5个线程!

为什么我一定要分批处理的道理就是为了每次试内存里的记录不要太多。

现在有个问题,这样的设计我做过

5个线程处理完后,自动销毁(每个线程处理完100条记录这个条件满足自动退出)

然后发觉还有数据,再创建5个线程

可是我发觉,在TOMAT里,刚开始5个线程开始运行时,从86变成了91,OK,5个线程在运行时,内存一直是91,这个没问题

然后问题来了,这5个线程结束了(我用程序是跟到了,确实5个线程结束了),再创建5个线程时,内存长到了96

这样一直下去我就担心内存是不是就一直上升,如果是1亿条记录,内存不就给耗完了?

因此我就觉得奇怪,前面5个线程结束时(满足线程运行条件结束,且所有的都关了),内存怎么没有施放?

是不是我这个设计还是有问题,请高人分析!

#17


你以上这个想法应该已经挺好了.
你担心的这个问题可以用System.gc();
而且最好用线程池.

#18


不懂  帮顶!

#19


引用 19 楼 Mr_Von 的回复:
不懂  帮顶!

顶!顶!!顶!!!

#20


把数据量切开分批次取出来再处理,对每批次使用线程池,处理完再取
类似于分页,只是多分一些,减少下内存消耗

菜鸟看法

#21


先记下,有空来看

#22


散分了,谢谢各位!

#1


线程池肯定要更好一些啊.
不一定要销毁线程啊,可以让它们Sleep直到有新的任务在唤醒它们啊.

#2


引用 1 楼 yeah920 的回复:
帮忙顶一下,让了解的人来解答.


按照您的意思就是,有任务来了就唤醒,是不就是说,如果我这个是一个导出数据成文件的程序,那这个进程的生命是随着我整个程序的开始而开始,结束而结束?

还有,您指的让它一直SLEEP是指WAIT()还是SLEEP(),如果是SLEEP(),如何弄醒它?

#3


帮顶

#4


帮顶一个 
期待着高手的到来

#5


不懂 楼主的意思 帮顶一下吧  

#6


用多线程,connection 池

#7


不是很清楚,但你可以将它放入一个时间里,当执行500后将时间停止,当再用时将时间打开即可

#8


没看明白,既然楼主有100万条记录,为什么处理完500条就让所有线程都歇着?

#9


引用 9 楼 ZXEOC 的回复:
没看明白,既然楼主有100万条记录,为什么处理完500条就让所有线程都歇着?


同问,本来使用线程就是想通过并行来提高效率,既然需要处理这么多的数据量为什么要分批次呢?
另外,关于数据库访问的貌似都是用连接池来处理的

#10


逻辑还是和数据库链接的使用一样的,要用生成,用完杀掉.......

一个处理类,继承自线程,里面有一个属性保存要处理的记录
启动后就运行你的记录处理逻辑,只处理获得的记录,处理完就完了,这个线程自动就会消失

一个主类,取记录,取够你想拆分的数量(100条)后,
就new一个处理类,把这100条记录传给他,让他start去处理
再取100条记录,再new一个处理类,再start

逻辑就应该是这样,至于说频繁生成线程销毁线程的开销,可以通过调节你的拆分数量来控制
另外,线程池也是为了优化这点而生的
但并不是说要保持住多少个线程让他wait在那里来处理,这不是一个好的业务逻辑

#11


另外,你还要一个逻辑上的错误

既然你有100W条记录,分5个线程,为什么是每个线程分配100条,然后等这些线程处理完100条了再分100条?
直接每个线程分配100W/5条就可以了啊,

至于你说的有100W条在内存
记录在不在内存,取决你什么时候取出来,而不是取决于你什么时候去处理

如果你不想占内存,你就每次取少部分取来处理,就像分页一样

#12


可以考虑先把数据存入队列,N条数据来的时候就先把数据原模原样的存入数据库,然后可以建立一个创建定时器,在定制任务,比如每个10秒 处理100条数据。
比如
cycletime=10000;
//创建定时器
Sender.timer = new Timer(true);
//定制任务
Sender.timer.schedule(new TimerTask() {
     public void run() {
new  SenderThread().start();
}
}, 0, cycletime);
红色部分就是每个多少时间生成一个新的发送数据的线程,每次从队列数据库中取出100条数据进行处理,当然数据从队列出来的时候是要考虑线程安全的。

#13


楼主好人我来绑定!!!

#14


占个位子,关注。

#15


关注。

#16


我再添一把油,我现在想到这样的设计:

还是5个线程,每个处理100条,一共假设有100万条记录

这5个线程处理完了500条数据后,自动销毁!

然后外层一个循环,再创建5个线程!

为什么我一定要分批处理的道理就是为了每次试内存里的记录不要太多。

现在有个问题,这样的设计我做过

5个线程处理完后,自动销毁(每个线程处理完100条记录这个条件满足自动退出)

然后发觉还有数据,再创建5个线程

可是我发觉,在TOMAT里,刚开始5个线程开始运行时,从86变成了91,OK,5个线程在运行时,内存一直是91,这个没问题

然后问题来了,这5个线程结束了(我用程序是跟到了,确实5个线程结束了),再创建5个线程时,内存长到了96

这样一直下去我就担心内存是不是就一直上升,如果是1亿条记录,内存不就给耗完了?

因此我就觉得奇怪,前面5个线程结束时(满足线程运行条件结束,且所有的都关了),内存怎么没有施放?

是不是我这个设计还是有问题,请高人分析!

#17


你以上这个想法应该已经挺好了.
你担心的这个问题可以用System.gc();
而且最好用线程池.

#18


不懂  帮顶!

#19


引用 19 楼 Mr_Von 的回复:
不懂  帮顶!

顶!顶!!顶!!!

#20


把数据量切开分批次取出来再处理,对每批次使用线程池,处理完再取
类似于分页,只是多分一些,减少下内存消耗

菜鸟看法

#21


先记下,有空来看

#22


散分了,谢谢各位!