Bootstrap

java workqueue_Java工作队列和线程池

背景

最近的需要做一个与设备通信的web项目。当然,我们需要写好与设备之间的通信协议(socket)。大致的时序逻辑时:当用户用浏览器点击页面某一控件后,它就向后台发送一个post请求,后台解析前台发送的参数,然后封装成相应的帧格式,然后与设备进行通信,设备接到指令后,完成相应的功能,然后将数据信息返回给后台服务器,后台服务器将这些返回的数据组织好,一方面返回给前台页面,一方面将数据存储到数据库中。

问题:

1.由于通信设备只允许一个socket与它通信,因此,所有的用户都需要共用一个socket,所以,在某一时刻,不能有2个用户同时使用socket

2.当很多条相同的指令以较短的时间间隔(1s左右)发送到通信设备时,通信设备只响应第一条,其他的不予响应。

解决方案

针对上述问题,我们就会想到通过使用队列和线程池来解决以上问题。我们可以将所有用户的指令依次放入队列中,线程池中只允许一个线程运行,而且线程执行完之后,还可以休眠一段时间,等通信设备反应过来的时候,再依次执行队列中的指令。

队列和线程池演示程序

1.WorkQueue.java

该类实现了队列和线程池,详见如下

/*

* $filename: WorkQueue.java,v $

* $Date: 2013-11-20 $

* Copyright (C) ZhengHaibo, Inc. All rights reserved.

* This software is Made by Zhenghaibo.

*/

package edu.njupt.zhb;

import java.util.LinkedList;

/*

*@author: ZhengHaibo

*web: http://blog.csdn.net/nuptboyzhb

*mail: [email protected]

*2013-11-20 Nanjing,njupt,China

*References:http://www.ibm.com/developerworks/java/library/j-jtp0730/index.html

*/

public class WorkQueue

{

private final int nThreads;//同时最多执行的线程个数

private final PoolWorker[] threads;//线程池

private final LinkedList queue;//线程队列

public WorkQueue(int nThreads)

{

this.nThreads = nThreads;

queue = new LinkedList();

threads = new PoolWorker[nThreads];

for (int i=0; i

threads[i] = new PoolWorker();

threads[i].start();

}

}

public void execute(Runnable r) {

synchronized(queue) {

queue.addLast(r);

queue.notify();

}

}

private class PoolWorker extends Thread {

public void run() {

Runnable r;

while (true) {

synchronized(queue) {

while (queue.isEmpty()) {

try

{

queue.wait();

}

catch (InterruptedException ignored)

{

}

}

r = (Runnable) queue.removeFirst();

}

// If we don't catch RuntimeException,

// the pool could leak threads

try {

r.run();

}

catch (RuntimeException e) {

// You might want to log something here

e.printStackTrace();

}

}

}

}

}

2.WorkThread.java

这是我们的工作线程,在这个Demo中,工作线程只做一件事:将number的值加1,然后休眠,最后打印一下当前number的值。由于number是静态变量,因此我们就可以模拟一下,工作队列的一个执行情况。

/*

* $filename: WorkThread.java,v $

* $Date: 2013-11-20 $

* Copyright (C) ZhengHaibo, Inc. All rights reserved.

* This software is Made by Zhenghaibo.

*/

package edu.njupt.zhb;

/*

*@author: ZhengHaibo

*web: http://blog.csdn.net/nuptboyzhb

*mail: [email protected]

*2013-11-20 Nanjing,njupt,China

*/

public class WorkThread extends Thread{

public static int number = 0;

@Override

public void run() {

// TODO Auto-generated method stub

try {

number = number + 1;

Thread.sleep(100);

System.out.println("number = "+number);

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

3.测试案例1

我们的线程池只允许一个线程同时执行,这样的结果是:打印number的值是从1-10顺序打印

/*

* $filename: TestMain.java,v $

* $Date: 2013-11-20 $

* Copyright (C) ZhengHaibo, Inc. All rights reserved.

* This software is Made by Zhenghaibo.

*/

package edu.njupt.zhb;

import java.util.ArrayList;

import java.util.List;

/*

*@author: ZhengHaibo

*web: http://blog.csdn.net/nuptboyzhb

*mail: [email protected]

*2013-11-20 Nanjing,njupt,China

*/

public class TestMain {

/**

* @param args

*/

public static void main(String[] args) {

// TODO Auto-generated method stub

WorkQueue workQueue = new WorkQueue(1);//只允许同时运行1个线程

for (int i = 0; i < 10; i++) {

WorkThread wThread = new WorkThread();

workQueue.execute(wThread);

}

}

}

运行结果是:

number = 1

number = 2

number = 3

number = 4

number = 5

number = 6

number = 7

number = 8

number = 9

number = 10

4.测试案例2

线程池中允许同时最多有5个线程一起执行

/*

* $filename: TestMain.java,v $

* $Date: 2013-11-20 $

* Copyright (C) ZhengHaibo, Inc. All rights reserved.

* This software is Made by Zhenghaibo.

*/

package edu.njupt.zhb;

import java.util.ArrayList;

import java.util.List;

/*

*@author: ZhengHaibo

*web: http://blog.csdn.net/nuptboyzhb

*mail: [email protected]

*2013-11-20 Nanjing,njupt,China

*/

public class TestMain {

/**

* @param args

*/

public static void main(String[] args) {

// TODO Auto-generated method stub

WorkQueue wQueue = new WorkQueue(5);//允许同时运行5个线程

for (int i = 0; i < 10; i++) {

WorkThread wThread = new WorkThread();

wQueue.execute(wThread);

}

}

}

运行结果是:

number = 5

number = 5

number = 5

number = 5

number = 5

number = 10

number = 10

number = 10

number = 10

number = 10

在某些场合中,如果能够承受100个线程同时运行,那么我们就将workqueue线程池的大小设成100,当线程超过100时,就将线程放入队列queue中,等有一些线程执行结束后,依次执行队列中的线程,一直执行到对列为空时,线程池中的100个线程都在等待新的任务加入。

未经允许不得用于商业目的

;