上代码:(代码有点长)
消费者代码:
//开发板发来的的信息
@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() {..........................
但是测试后的结果是(数据库中):

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