如何更优雅地实现下面一段逻辑(不使用 Thread.sleep())?

2018-07-19 21:23:59 +08:00
 terry0314
for (Integer id : ids) {
    int result = doSomething(id);
    while (result == someValue) {
    	Thread.sleep(10 * 1000);
        result = doSomething(id);
    }
    
    int anotherResult = doAnotherThing(result);
    while (anotherResult == anotherValue) {
    	Thread.sleep(10 * 1000);
        anotherResult = doAnotherThing(result);
    }
}

感觉两个 sleep 用在这里不太合适也不太优雅,必须用 try catch 把相应的代码块给包起来

考虑用 ScheduledExecutorService 或者 delayQueue 实现,但是感觉前者需要另外开一个线程不太合适,因为我只需要一个线程来执行这个逻辑

V 友们有更好的解决办法吗

3940 次点击
所在节点    Java
20 条回复
lcorange
2018-07-19 21:30:44 +08:00
为什么要 sleep???有点看不懂诶,result 的值不是已经返回了么,在等什么呢?
lcorange
2018-07-19 21:33:45 +08:00
看明白了,要做个定时任务去查东西啊,你看看下面这四个库哪个用的舒服
https://www.ibm.com/developerworks/cn/java/j-lo-taskschedule/
Timer
ScheduledExecutor
开源工具包 Quartz
开源工具包 JCronTab
seaswalker
2018-07-19 21:33:58 +08:00
使用 listener ?线程完事了自己去通知别人呗
terry0314
2018-07-19 21:43:28 +08:00
@lcorange 我比较倾向于 ScheduledExecutor,但是问题在于其实我所有的流程都应该在一个线程中完成,因为现在的场景是 doSomething 这个方法是串行处理的的,doAnotherThing 方法又依赖于特定的 doSomething 返回值,如果我用 ScheduledExecutor 会创建新的线程,这个时候主线程也没有办法继续进行
lcorange
2018-07-19 21:54:26 +08:00
@terry0314 如果是这样的话,你看看 concurrent 包下的 Future 会不会让你觉得代码好看些
主线程的 Future.get()阻塞在这里,doSomething 的线程辟命的串行处理,然后处理结束后用 Future 来返回数据
woscaizi
2018-07-19 22:10:58 +08:00
你这个程序设计思路有问题吧。
Raymon111111
2018-07-19 22:14:12 +08:00
延迟队列

做完一个动作直接发延迟消息, 10 秒后接到再处理.
woscaizi
2018-07-19 22:15:57 +08:00
doSomeThing(id)方法的返回值不一样,说明方法内涉及到变化的数据,而你想用 while 循环来检测这种变动,我觉得不合理。
zjp
2018-07-19 22:16:36 +08:00
回调+1
现在这样怎么保证等待 10 * 1000 足够长又不会白等
woscaizi
2018-07-19 22:19:13 +08:00
另外如果 while 循环始终不跳出,程序就阻塞在这里了。
如果要检测数据变化,在单独的线程中处理比较好。
letitbesqzr
2018-07-19 22:20:13 +08:00
我也有一个类似的需求,一个简单的任务队列,因为数据量小,加上项目中没有其他需求使用到任务队列的地方了(系统里使用了 redis ),所以直接使用了 redis LPUSH RPOP 来做了一个简单的队列,在项目启动的时候 新建一个线程,一个 while 死循环,然后 RPOP 拿 redis list 是否有值,没有值就 sleep 3s 后再试。

不知道这种需求,有没有其他比较优雅的实现方式?
terry0314
2018-07-19 22:41:08 +08:00
@zjp
@woscaizi
doSomething 实际是调用了一个 HTTP 接口针对某一个 id 进行一些任务返回值代表任务是否完成,并且这个接口是串行的,对与每个 id 所需要的处理时间不一定相同,可能从 1 分钟 到 30 分钟不等,我也没有太好的办法确定一个合适的值所以每隔 10s 发起一次请求
woscaizi
2018-07-19 22:41:18 +08:00
@letitbesqzr 使用消息队列实现比较优雅,如果你可以主动通知的话。不然,你目前的方式应该是最优雅的。
terry0314
2018-07-19 22:42:43 +08:00
@terry0314 串行的意思是一个任务没有处理完场的时候再有其他请求来必定会返回失败
woscaizi
2018-07-19 22:51:30 +08:00
@terry0314 你的 ids 循环,每一个循环都堵塞等待执行结果的话,第一个循环和最后一个可能相差了很长很长时间,如果别的方法需要操作它们涉及的数据的话,就不准确了。
kevinhwang
2018-07-19 23:47:43 +08:00
不知道你的服务用于干嘛,如果并发高点很容易线程溢出。
sleep 这个函数还是尽量少在服务端用,用也不要睡太久。
kingsonl
2018-07-20 00:20:49 +08:00
回调或者消息队列(其实做的事情原理一样~)
WhoMercy
2018-07-20 08:14:14 +08:00
示例代码核心就是两轮串行的轮询,如果需要灵活配置某些参数、更好的监管控制,可以参考下这个工具( RxJava )
https://blog.csdn.net/lianwudi89/article/details/78619372
seancheer
2018-07-20 09:45:48 +08:00
搞个定时任务,然后该定时任务专门负责此类工作。。其他需要此类逻辑的自行向定时任务 register 自己的 target 和一个 callback,定时任务检测所有已经 register 的服务,当某个服务请求满足后,调用该服务的 callback。
terry0314
2018-07-20 10:21:09 +08:00
@seancheer 准备用这个思路了,不过最后选择了用 delayQueue 加线程池的方式实现

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/472477

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX