V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
terry0314
V2EX  ›  Java

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

  •  
  •   terry0314 · 2018-07-19 21:23:59 +08:00 · 3951 次点击
    这是一个创建于 2317 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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 友们有更好的解决办法吗

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

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

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