java定时定量提交_用生产消费者模式实现数据队列定时或定量的异步存储

需求:

最近在考虑IM软件服务器端编程,有这样一个需求,就是把用户发的信息,全部保存到数据库中,如果是一般的web应用,可能就直接把用户提交的数据写入数据库了,但IM的信息的特点时,需要响应快(实时处理),数据量大,根据这个特点,我设计成接收转发模块与数据写入数据库为不同的模块,很明显,他们满足生产消费者模式,即某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。生产者与消费者并没有构成生产消费者模式,而生产者生产的数据由消费者消费的过程才能构成生产消费者模式。

设计:

生产者和消费者模式实现方式很多,但在实现的时候我们至少需要考虑生产消费解耦、支持并发、支持生产消费忙闲不均的情况。

一、解耦

假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。这个缓冲区我们可以用一个列队实现。

二、支持并发(concurrency)

生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会白白糟蹋大好时光。

使用了生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体。生产者把制造出来的数据往缓冲区一丢,就可以再去生产下一个数据。基本上不用依赖消费者的处理速度。其实当初这个模式,主要就是用来处理并发问题的。这样高并发下,用户感觉响应很快:)

三、支持忙闲不均

缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。

除了以上三个需要考虑的,在我的项目中,我还要考虑与数据库的交互不能太频繁,只能满足一定数据量时,使用批量方式写入数据库(定量写入),这个实现本身很简单,但如果考虑到服务器清闲时,很长时间都达不到这个数据量,但这段时间内可能会停机,没有写入数据库的数据就可能丢失,所以在给定的一段时间里,数据量没有到达给定数据的条件,只要达到时间条件,也需要写入数据库。

实现:

基于以上的想法,我们可以使用java.util.concurrent.BlockingQueue来实现,这里仅分析一些关键代码

1、构造一个用于数据缓冲区的队列

1

final static BlockingQueue queue = new LinkedBlockingQueue();

2、生产者生产的数据放入队列

1

2

3

4

5

6

7

8

// 本方法由生产者调用,将生产的数据放入队列

public static void add(Message m) {

try {

queue.put(m);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

3、消费者对产生的数据进行消费

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

@Override

public void run() {

try {

while (true) {

consume(queue.take());

}

} catch (InterruptedException ex) {

ex.printStackTrace();

}

}

void consume(Message message) {

synchronized(list) {

list.add(message);

if(list.size() == 100){

insert("满足100");

}

}

}

4、把数据批量写入数据库

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

void insert(String type){

synchronized(list) {

if(list.size() < 1)

return ;

System.out.println(type);

String name = Thread.currentThread().getName();

for(Message message : list){

log.debug("消费者:"+message.toString()+" ---"+name+" "+type);

}

list.clear();

}

}

}

5、满足时间条件时,批量把数据写入数据库

1

2

3

4

5

6

7

8

9

10

11

class TimerInsert extends TimerTask{

Consumer consumer;

TimerInsert(Consumer consumer){

this.consumer = consumer;

}

@Override

public void run() {

consumer.insert("满足时间");

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值