JAVA熟悉队列的来看看这段代码,看有没有问题 集思广益一下

二号铺 发布于 08/22 12:21
阅读 1K+
收藏 0

大家看看这段代码有什么问题吗? 


import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.LinkedBlockingQueue;

@Service
@Slf4j
public class WaybillTmsRepairZJServiceImpl implements InitializingBean {

    @Autowired
    private xxxService xxxService;

    private static LinkedBlockingQueue<SaveZJToDoReq> queue = new LinkedBlockingQueue();//offer take

    public void offer(SaveZJToDoReq req){
        queue.offer(req);//超过容量则放弃
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    try{
                        SaveZJToDoReq req = queue.take();
                        
                        xxxService.save(req.getPlateNo(),  req.getBeginTimeTmp(),  req.getEndTimeTmp(),req.getWaybillId(),true);
                    }catch (InterruptedException e){
                        log.error("被中断");
                        //Thread.currentThread().interrupt();
                    }catch (Exception e){
                        log.error("失败",e);//不能影响正常流程
                    }
                }
            }
        },"xxxocation-thread");
        thread.start();
    }
}
 

以下是问题补充:

@二号铺:业务场景是这样的:页面导入最多包含500条的excel文件,主数据在解析完同步保存到数据库;然后这个队列主要处理逻辑是调用第三方接口,然后再把第三方接口返回的数据保存到数据库; qps不高 (08/27 22:07)
加载中
0
哈哈哈你猜我是谁
哈哈哈你猜我是谁

有,如果机器异常挂掉了怎么办?如果没异常挂掉需要升级版本重启机器怎么办?

哈哈哈你猜我是谁
哈哈哈你猜我是谁
回复 @二号铺 : 不需要
二号铺
二号铺
回复 @King_Liu : 忘了最重要的事情了,我的for循环里有没有必要Thread.sleep?调用保存方法大概是1-2s耗时
哈哈哈你猜我是谁
哈哈哈你猜我是谁
回复 @King_Liu : 上消息中间件啊,配合消息ACK机制基本上问题不大。
哈哈哈你猜我是谁
哈哈哈你猜我是谁
回复 @二号铺 : 那就得看你offer的qps,而且这不是主要的,系统资源这种东西不行加机器就完事了,对数据时序有要求加个version字段就行,主要还是需要考虑宕机的场景。
二号铺
二号铺
会不会有大量消耗系统资源的风险?循环里是一个大概耗时2s的操作
下一页
0
脸泛微红

多个请求同时发起就是一个多线程了吧,这样没办法保证数据不脏读吧

 

0
前端大师傅
前端大师傅

虽然代码就只几行,但问题非常大。你这个代码的用意应该是开了一个线程去处理offer请求然后保存起来,虽然你是用的LinkedBlockingQueue容器去依次请求,但处理是单线程,并不会有并发问题。主要的问题还是一楼所说的。二楼则是根本没看懂代码的意思,胡说八道,看到线程就说啥多线程,人家代码就一个工作线程+队列处理。你的线程里没有做安全退出的处理。只有一个InterruptedException 来推断退出。然后调用Thread.currentThread().interrupt()来退出当前线程,其实你这里写错了。退出当前线程并不要手动去interrupt掉,而是中断这个while循环,跑完这段代码即可。

我不知道楼主连这种基本的思想都不知道,具体能写出这段代码。在下的意思是能写得出这段代码的人,怎么会不知道中断退出的含义。

另从性能的角度看最好不要通过外部线程中止,内部用try catch来捕获异常的方法来中断线程,这样不但很low,而且一看就是没认真读过人家jdk设计的原意。最好采用token来做一个中断source(源)这里的tokensource相当于一个给外部中断加了一条引线,从而优雅的停掉你的线程while循环。

 

飞奔地蜗牛
飞奔地蜗牛
最后一句没看懂咋做
0
c
cm1031

那具体应该怎么中断while循环呢,请教一下

0
二号铺
二号铺

引用来自“前端大师傅”的评论

虽然代码就只几行,但问题非常大。你这个代码的用意应该是开了一个线程去处理offer请求然后保存起来,虽然你是用的LinkedBlockingQueue容器去依次请求,但处理是单线程,并不会有并发问题。主要的问题还是一楼所说的。二楼则是根本没看懂代码的意思,胡说八道,看到线程就说啥多线程,人家代码就一个工作线程+队列处理。你的线程里没有做安全退出的处理。只有一个InterruptedException 来推断退出。然后调用Thread.currentThread().interrupt()来退出当前线程,其实你这里写错了。退出当前线程并不要手动去interrupt掉,而是中断这个while循环,跑完这段代码即可。

我不知道楼主连这种基本的思想都不知道,具体能写出这段代码。在下的意思是能写得出这段代码的人,怎么会不知道中断退出的含义。

另从性能的角度看最好不要通过外部线程中止,内部用try catch来捕获异常的方法来中断线程,这样不但很low,而且一看就是没认真读过人家jdk设计的原意。最好采用token来做一个中断source(源)这里的tokensource相当于一个给外部中断加了一条引线,从而优雅的停掉你的线程while循环。

 

你没有明白我的用意,我的目的是为了保证while循环线程一直处理队列里的任务(只要里面有任务);

至于你说的我用“Thread.currentThread().interrupt()来退出当前线程”来退出当前线程???

我完全没有这个意思,我下面代码是注释了的,调用这个代码只是为了告诉其他持有该线程的栈,因为在rty-catch捕获到 interruptException后,线程中断标志会被重置(不信你就自己试试),我这里如果手动设置一下还是很负责任的做法;

 

二号铺
二号铺
回复 @前端大师傅是垃圾 ::fearful::neckbeard::neckbeard:
前端大师傅是垃圾
前端大师傅是垃圾
不要跟这个前端大师傅讨论了。他压根就看不懂。 他是个前端大师傅。 写代码用C#。现在来评论你的Java. 而且他还是个30多年前就做运维现在50多岁还在一线奋斗的程序员。
0
二号铺
二号铺

引用来自“cm1031”的评论

那具体应该怎么中断while循环呢,请教一下

如果你想终duan这个线程,很简单啊
可以在捕获Interrupt,或者是判断 Thread.currentThread().isInterrupted() 后用return,break都可以;

0
二号铺
二号铺

引用来自“前端大师傅”的评论

虽然代码就只几行,但问题非常大。你这个代码的用意应该是开了一个线程去处理offer请求然后保存起来,虽然你是用的LinkedBlockingQueue容器去依次请求,但处理是单线程,并不会有并发问题。主要的问题还是一楼所说的。二楼则是根本没看懂代码的意思,胡说八道,看到线程就说啥多线程,人家代码就一个工作线程+队列处理。你的线程里没有做安全退出的处理。只有一个InterruptedException 来推断退出。然后调用Thread.currentThread().interrupt()来退出当前线程,其实你这里写错了。退出当前线程并不要手动去interrupt掉,而是中断这个while循环,跑完这段代码即可。

我不知道楼主连这种基本的思想都不知道,具体能写出这段代码。在下的意思是能写得出这段代码的人,怎么会不知道中断退出的含义。

另从性能的角度看最好不要通过外部线程中止,内部用try catch来捕获异常的方法来中断线程,这样不但很low,而且一看就是没认真读过人家jdk设计的原意。最好采用token来做一个中断source(源)这里的tokensource相当于一个给外部中断加了一条引线,从而优雅的停掉你的线程while循环。

 

你说while 循环里用try很low ,那你说该怎么写才能达到我的目的?目标:线程要处理队列里的任务,只有里面有任务就要处理

前端大师傅
前端大师傅
回复 @前端大师傅 : 那就更有问题了,任何的任务处理都应该留有一个中断结束的方法或未实现接口。让调用者去实现这个接口来结束。否则无论是web还是控制台,万一使用者点了关闭应用或应用意外中止时,你这个程序不就死掉了?必须要留中断还有中断后如何处理的接口。
二号铺
二号铺
回复 @前端大师傅 : 问题是我不想中断它:joy:
前端大师傅
前端大师傅
不是说了吗,有tokenSouce进行处理中断退出,而且请注意,线程的中断方法并不是中断当前程序,而是发出中断信号,这时线程里的代码会抛出中断异常,1.你这个归属Thread的方法不能中断当前线程,只是让其出现异常,然后你在异常里退出。这种就违背的设计者在设计这个Thread类的初衷。2.退出可以参考TokenSource的做法。
0
J
JavaMVC

对列不加锁,会有问题的,你这是线程不安全的

二号铺
二号铺
回复 @JavaMVC : 是这样的:queue.offer(req); 这个操作是提供给其他线程来调用的,这个方法的调用不会受里面元素多少影响; 如果某一个时刻队列里元素为空了,名字为“xxxocation-thread”的线程会阻塞在queue.take()这一行,程序不会往下走,如果下一刻main线程放了一个元素到队列里,则“xxxocation-thread”这个线程会马上被唤醒
J
JavaMVC
回复 @二号铺 : 还有个问题,你的queue.take()为空会阻塞;但是你 queue.offer(req);会唤醒吗?
二号铺
二号铺
LinkedBlockingQueue 的offer操作是线程安全的呢:sunglasses:
0
魔法王者安琪拉
魔法王者安琪拉

问题点不大,看你用的是Spring框架,Spring默认是单例模式没必要用static对像,LinkedBlockingQueue是线程安全的,通过ReentrantLock锁来控制,所以也不存在线程安全的问题,唯一有漏洞的地方,就是业务模块,获取队列数据时要判空操作,要不while(true)会把db的资源耗光的,到时就是拿不到数据源异常,其它这种模式只适合于单机模式,集群的话还是考虑mq框架

二号铺
二号铺
忘了最重要的事情了,我的for循环里有没有必要Thread.sleep?调用保存方法大概是1-2s耗时
前端大师傅是垃圾
前端大师傅是垃圾
回复 @二号铺 : 我第一次看。还有疑问呢。假如有100个进队列。我第50个出错了。 try catch之后退出循环了。 剩下的50个你是不是不做处理了??后来一看原来是抓了异常进日志继续跑哈哈。问题不大。吓尿我了
二号铺
二号铺
嗯 目前暂时考虑单机模式
0
前端大师傅是垃圾
前端大师傅是垃圾

 while(true)都死循环了

魔法王者安琪拉
魔法王者安琪拉
回复 @二号铺 : :smirk:确实
二号铺
二号铺
下面的 queue.take 操作会在没有元素的时候阻塞,不会死循环哈
返回顶部
顶部