Java 服务器示例
在本文剩余部分我们将应用在前面章节中介绍的一些想法使用 Java 类库中的 Executors 服务构建一个相对简单的 Java 服务器应用程序只需少量应用程序代码Executors 服务就可以用于创建一个服务器来管理工作者线程池如清单 所示
清单 使用 Executors 服务的 Server 和 TaskHandler 类
import ncurrentExecutors;
import ncurrentExecutorService;
import ncurrentThreadFactory;
class Server {
private ExecutorService threadPool;
Server(int numThreads) {
ThreadFactory theFactory = new ThreadFactory();
thisthreadPool = ExecutorsnewFixedThreadPool(numThreads theFactory);
}
public void start() {
while (true) {
// main server handling loop find a task to do
// create a TaskHandler object to complete this operation
TaskHandler task = new TaskHandler();
thisthreadPoolexecute(task);
}
thisthreadPoolshutdown();
}
public static void main(String[] args) {
int serverThreads = IntegerparseInt(args[]);
Server theServer = new Server(serverThreads);
theServerstart();
}
}
class TaskHandler extends Runnable {
public void run() {
// code to handle a task
}
}
此服务器可以创建所有需要的线程直到达到创建服务器(从此示例中的命令行解码)时指定的最大数量每个工作者线程使用 TaskHandler 类执行一部分工作出于我们的目的我们将创建一个 TaskHandlerrun() 方法它每次运行都应该花相同的时间因此执行 TaskHandlerrun() 的时间上的任何易变性都源自于底层 JVM 中的暂停或易变性某个线程问题或在堆栈的较低级别上引入的暂停清单 给出了 TaskHandler 类
清单 具有可预测性能的 TaskHandler 类
import javalangRunnable;
class TaskHandler implements Runnable {
static public int N=;
static public int M=;
static long result=L;
// constant work per transaction
public void run() {
long dispatchTime = SystemnanoTime();
long x=L;
for (int j=;j < M;j++) {
for (int i=;i < N;i++) {
x = x + i;
}
}
result = x;
long endTime = SystemnanoTime();
ServerreportTiming(dispatchTime endTime);
}
}
此 run() 方法中的循环计算 N () 个整数中前 M () 个整数的和M 和 N 的值已经选定以便运行循环的事务时间为 毫秒左右使一项操作可以被一个 OS 调度限额(通常持续约 毫秒)中断我们在此计算构造此循环的目的在于使 JIT 编译器能够生成将执行高度可预测的时间量的出色代码run() 方法不会显式在对 SystemnanoTime() 的两次调用中显式阻塞这两次调用用于计算循环运行的时间由于上述代码高度可预测所以我们可以使用它来展示延迟和易变性的不一定来源于您测试的代码
我们使此应用程序稍微真实一些在运行 TaskHandler 代码时激活垃圾收集器子系统清单 给出了这个 GCStressThread 类
清单 用于不断生成垃圾的 GCStressThread 类
class GCStressThread extends Thread {
HashMap<IntegerBinaryTree> map;
volatile boolean stop = false;
class BinaryTree {
public BinaryTree left;
public BinaryTree right;
public Long value;
}
private void allocateSomeData(boolean useSleep) {
try {
for (int i=;i < ;i++) {
if (useSleep)
Threadsleep();
BinaryTree newTree = createNewTree(); // create full level BinaryTree
thismapput(new Integer(i) newTree);
}
} catch (InterruptedException e) {
stop = true;
}
}
public void initialize() {
thismap = new HashMap<IntegerBinaryTree>();
allocateSomeData(false);
Systemoutprintln(\nFinished initializing\n);
}
public void run() {
while (!stop) {
allocateSomeData(true);
}
}
}
GCStressThread 通过 HashMap 维护一组 BinaryTree它为存储新 BinaryTree 结构的 HashMap 迭代一组相同的 Integer 键这些结构是完全填充的 级 BinaryTrees(所以每个 BinaryTree 有 = 个节点被存储在 HashMap 中)HashMap 在每次迭代时都持有 个 BinaryTree(活动数据)它每隔 毫秒就会将其中一个节点替换为新的 BinaryTree通过这种方式此数据结构维持着一个相当复杂的活动对象集并且以特定速率生成垃圾首先使用 initialize() 例程借助 个 BinaryTree 来初始化HashMapinitialize() 例程不会在对每棵树的收集之间暂停一旦启动了 GCStressThread(在启动服务器之前)它将通过服务器的工作者线程全权处理 TaskHandler 操作
我们不打算使用客户端来驱动此服务器我们将直接在服务器的主循环(在 Serverstart() 方法中)中创建 NUM_OPERATIONS == 操作清单 给出了 Serverstart() 方法
清单 在服务器内部分派操作
public void start() {
for (int m=; m < NUM_OPERATIONS;m++) {
TaskHandler task = new TaskHandler();
threadPoolexecute(task);
}
try {
while (!serverShutdown) { // boolean set to true when done
Threadsleep();
}
}
catch (InterruptedException e) {
}
}