关于消费者被唤醒的又一个问题

上代码:(代码有点长)

消费者代码:
//开发板发来的的信息

@RequestMapping("/produce")
public void produce(HttpServletRequest request, HttpServletResponse response, KaiFaBan kaiFaBan){
    System.out.println("《生产者》的信息是:"+kaiFaBan.getName()+",获得的数据是:"+kaiFaBan.getCount());
    Runnable producter=new Runnable() {
        @Override
        public synchronized void run() {
            while (flag){
                try {
                    KaiFaBan k=new KaiFaBan();
                    k.setName("开发板1");
                    k.setCount(-1);
                    //"毒丸"标记
                    queue.put(k);
                    flag=false;
                    System.out.println("毒丸已经放入");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                if(kaiFaBan != null){
                    queue.put(kaiFaBan);//阻塞
                    System.out.println("《生产者》把消息已存入队列中");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    exec.execute(producter);
}

//消费者代码

 @RequestMapping("/consumer")
public void consumer(HttpServletRequest request, HttpServletResponse response) {
    Runnable consumer = new Runnable() {
        @Override
        public void run() {
            System.out.println("开启《消费者》...");
            while(true){
                try {
                    KaiFaBan takeValue = queue.take();//阻塞
                    //这是“毒丸”对象
                    synchronized (waitLock){
                        while(takeValue.getCount() == -1 || biaoJi == true){
                            //把biaoJi变为true
                            biaoJi=true;
                            System.out.println("消费者已经停下来了,,,,,,,,,,,,,,,,,,,,,,,,,,,,》");
                            //消费者线程等待(让消费者线程停下来)
                            waitLock.wait();
                            System.out.println("消费者被唤醒,,,,,,,,,,,,,,,,,,,,,,,,,,,,》");
                        }
                    }
                    //逻辑运算
                    synchronized (myLock) {
                        if (takeValue != null) {
                            if (takeValue.getName().equals("开发板1")) {
                                if (KAFABANNUMBER1 < takeValue.getCount()) {
                                    KAFABANNUMBER1 = takeValue.getCount();
                                    System.out.println("KAFABANNUMBER1:" + KAFABANNUMBER1);
                                }else{
                                    System.out.println("else方法中,KAFABANNUMBER1:"+ KAFABANNUMBER1);
                                }
                            } else if (takeValue.getName().equals("开发板2")) {
                                if (KAFABANNUMBER2 < takeValue.getCount()) {
                                    KAFABANNUMBER2 = takeValue.getCount();
                                    System.out.println("KAFABANNUMBER2:" + KAFABANNUMBER2);
                                }else{
                                    System.out.println("else方法中,KAFABANNUMBER2:"+ KAFABANNUMBER2);
                                }
                            } else if (takeValue.getName().equals("开发板3")) {
                                if (KAFABANNUMBER3 < takeValue.getCount()) {
                                    KAFABANNUMBER3 = takeValue.getCount();
                                    System.out.println("KAFABANNUMBER3:" + KAFABANNUMBER3);
                                }else{
                                    System.out.println("else方法中,KAFABANNUMBER3:"+ KAFABANNUMBER3);
                                }
                            }
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    exec.execute(consumer);
}

//一段时间后让消费者停下来,处理完逻辑后又唤醒消费者

  //一个小时后取出数据(把多线程变为单线程)
@RequestMapping("/setTestTime")
public void setTestTime(HttpServletRequest request,HttpServletResponse response){
    ServletContext servletContext = request.getServletContext();
    ApplicationContext applicationContext = (ApplicationContext) servletContext.getAttribute("applicationContext");
    FenPeiService s= (FenPeiService) applicationContext.getBean("fenPeiServiceId");
    while (true){
        try {
            //先用20秒钟测量
            Thread.sleep(15*1000);
            System.out.println("测试时间15秒到了,开始处理数据");
            //把标记flag变为ture,以便把“毒丸”加入到队列中
            flag=true;
            while (true) {
                //如果biaoji==true,那么说明所有的消费者线程进入了等待
                if (biaoJi) {
                    //长耗时工作
                    System.out.println("开始处理IO等其他耗时工作");
                    //线程开启长耗时工作
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            //从数据库中获取数据
                            try {
                                //这里的“前”对应的是“开发板1”
                                if (s.searchLocation("前", KAFABANNUMBER1)) {
                                    //更新数据库
                                    s.update("前", KAFABANNUMBER1);
                                }
                                //这里的“中”对应的是“开发板2”
                                if (s.searchLocation("中", KAFABANNUMBER2)) {
                                    //更新数据库
                                    s.update("中", KAFABANNUMBER2);
                                }
                                //这里的“后”对应的是“开发板3”
                                if (s.searchLocation("后", KAFABANNUMBER3)) {
                                    //更新数据库
                                    s.update("后", KAFABANNUMBER3);
                                } else {
                                    //分为3种情况;1、生产了,生产后的单个小时数量小于前一个小时的数量;
                                    //2、生产了,生产后的单个小时数量等于前一个小时的数量;
                                    //3、根本就没有生产,意思就是未分配任务
                                    System.out.println("数据库保持不变,不进行更新");
                                }
                                //获取当前系统时间
                                Date date = new Date();
                                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                String format = simpleDateFormat.format(date);
                                //不管更不更新,都要把记录保存到新的数据库;并且在页面展示
                                List<FenPei> serach = s.serach();
                                if (serach.size() != 0) {
                                    Iterator<FenPei> iterator = serach.iterator();
                                    while (iterator.hasNext()) {
                                        FenPei next = iterator.next();
                                        if (next.getLocation().equals("前")) {
                                            String valueOf = String.valueOf(KAFABANNUMBER1);
                                            next.setCount(valueOf);
                                            next.setTime(format);
                                            try {
                                                //在这里进行数据库保存操作(生产数据库记录)
                                                s.saveToLog(next);
                                            } catch (PropertyVetoException e) {
                                                e.printStackTrace();
                                            }
                                        }
                                        if (next.getLocation().equals("中")) {
                                            String valueOf = String.valueOf(KAFABANNUMBER2);
                                            next.setCount(valueOf);
                                            next.setTime(format);
                                            try {
                                                //在这里进行数据库保存操作(生产数据库记录)
                                                s.saveToLog(next);
                                            } catch (PropertyVetoException e) {
                                                e.printStackTrace();
                                            }
                                        }
                                        if (next.getLocation().equals("后")) {
                                            String valueOf = String.valueOf(KAFABANNUMBER3);
                                            next.setTime(format);
                                            try {
                                                //在这里进行数据库保存操作(生产数据库记录)
                                                s.saveToLog(next);
                                            } catch (PropertyVetoException e) {
                                                e.printStackTrace();
                                            }
                                        }
                                    }
                                } else {
                                    System.out.println("所有生产任务还未分配,无法操作");
                                }
                                //最后还要把全局变量变为0
                                KAFABANNUMBER1 = 0;
                                KAFABANNUMBER2 = 0;
                                KAFABANNUMBER3 = 0;
                            } catch (SQLException throwables) {
                                throwables.printStackTrace();
                            } finally {
                                countDownLatch2.countDown();
                            }
                        }
                    }).start();
                    //等待一个子线程运行结束后,主线程在运行
                    countDownLatch2.await();
                    synchronized (waitLock) {
                        System.out.println("完成IO等其他耗时工作");
                        //把biaoJi重新置为false
                        biaoJi = false;
                        //唤醒消费者线程
                        waitLock.notifyAll();
                        System.out.println("唤醒消费者.。。。。。。。。。。。。。。。。。");
                    }
                    //退出循环
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

疑问:在setTestTime()方法中最后有这么一段:

synchronized (waitLock) {
                    System.out.println("完成IO等其他耗时工作");
                    //把biaoJi重新置为false
                    **biaoJi = false;**
                    //唤醒消费者线程
                    waitLock.notifyAll();
                    System.out.println("唤醒消费者.。。。。。。。。。。。。。。。。。");
                }
                

其中,我已经把biaoJi改成了false,那么应该就不会进入到其中:(我本来想的是,我已经把biaoJi改成了false,并且用voliate修饰;应该不会进入其中??????)

 
 if (biaoJi) {
                //长耗时工作
                System.out.println("开始处理IO等其他耗时工作");
                //线程开启长耗时工作
                new Thread(new Runnable() {..........................

但是测试后的结果是(数据库中):
![](/img/bVcR3kO)
阅读 1.3k
1 个回答

大概看明白了,你是不是两次连续请求?如果是两次连续请求,在第二个线程进入的时候还没有为false 吧,就会重复运行长时任务,你这种写法,只能等任务运行完成后,在发送test才能不重复运行长时间任务。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题