关于java异步的问题。

发布于 2022-09-06 10:20:43 字数 270 浏览 15 评论 0

有一张邮件表,存储三个字段:
发送人,发送是否成功,发送内容

在spring mvc中有一个task,每5秒轮询一次这个表,查询出未发送成功的数据,并进行再次发送,发送成功后再更新表记录设置为发送成功。

这里存在一个问题,如果第一次轮询发现有未发送成功的邮件并进行发送,但是在发送的过程中开始了5秒后的第二次轮询,由于第一次没发送完所以表记录还是未发生成功,这时候会造成发送重复邮件。
请教有什么建议的解决方案吗?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

乖乖兔^ω^ 2022-09-13 10:20:43

我说一个方案吧:
再增加一个字段status字段标记当前邮件的处理状态,比如status=0 未处理,status=1代表正在处理,status=2表示处理完成。
每次轮询未发送的邮件WHERE status=0 AND isSend = false
开始发送邮件更新status=1
异步发送完成更新status=2

其实你这个问题的症结在于发送是否成功这个字段只能表达是/否两种场景

潜移默化 2022-09-13 10:20:43

如果你使用的是0/5 ? 这种表达式,并且发送右键是同步的(这里理解为可以拿到发送的结果),即使发送邮件超时也是没关系的,因为一个5秒执行不完的时候,会等到下一个周期才开始执行。
例如最近五次的运行时间为

2018/1/7 17:32:45
2018/1/7 17:32:50
2018/1/7 17:32:55
2018/1/7 17:33:00
2018/1/7 17:33:05

如果在2018/1/7 17:32:45秒的任务到了2018/1/7 17:32:50还没有执行完成,将不会再触发2018/1/7 17:32:50的任务,而是等到2018/1/7 17:32:55的时候才会继续执行。

梦纸 2022-09-13 10:20:43

看你的应用架构:
如果是单应用(如一个tomcat),那就简单啦而且方法很多,总的来说是全部协作在内存中处理啦:
第一种方法:
1.1 使用同步的集合保存正在处理的数据(数据结构自己选),集合有list, set, map,同步的话,可以自己实现synchronized或使用ConcurrentHashMap等同步的集合。
1.2 每次你的task去处理任务时,从获取数据库时排除掉同步集合里的数据。怕遇到并发的问题的话,可以采用二次校验,从数据库拿出来后,判断同步集合里是否已经存在此数据了
1.3 task处理完数据后,就更新回去。
第二种方法:
2.1 使用队列,如LinkedBlockingDeque,每次task从数据库拿出数据(不更新数据库数据),放入队列中,然后由一个线程池里的单线程来处理队列中的数据,由这单线程来更新数据。

如果是集群分布式的,可采用以下方法,总的来说是利用中间件来进行同步(锁定):
第一种方法:
task拿出数据后,将数据库中对应的数据更新为中间状态(如正在处理),然后进行处理该数据。当下次task去处理任务时,从获取数据库时排除掉状态为中间状态(正在处理)的数据。其实这个方法也有可能遇到并发问题,可以使用乐观锁的形式来处理数据,将数据更新为中间状态时,采用乐观锁,保证数据未被改变过。

第二种方法(类似上述单应用的第一种方法,只不过此次不是使用本地的内存,而是使用redis的内存)
task拿出数据后(不更新数据库数据),将此数据放入redis中,然后进行处理该数据。当下次task去处理任务时,从获取数据库时排除掉redis里的数据,然后再处理数据。

挽梦忆笙歌 2022-09-13 10:20:43

印象中java里是有同步锁来解决多线程的安全问题的,你可以百度一下

你的呼吸 2022-09-13 10:20:43
  1. 定时器时间加长
  2. 利用线程同步锁
  3. 提高sql执行效率
赠佳期 2022-09-13 10:20:43

首先安排5s轮询并不合理,队列大小不确定,timtout不确定,线程池不确定。所以执行一次发送话费的时间不确定。
个人觉得理想的情况是每一次轮询执行完成后安排一个计划任务(前提是自己邮件服务器执行发送,如果第三方服务发送邮件也是异步的,可能不能获取邮件是否发送成功),这样不会存在冲突。

单独轮询,然后添加到队列的话,重复不可避免的。比如说在轮询过程中,有一个邮件发送成功了,而在状态更新到数据库之前已经查询了状态,这就不可避免要重复了。这种情况要避免的话,要增加中间环节,增加了程序复杂度,而且也不能保证百分百。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文