java endpoint作用_tomcat-JIoEndpoint解析

JIoEndpoint是tomcat中处理socket通讯服务器端的默认类。

主要功能有:

1:开启一个(默认)或者多个Deamon线程(Acceptor),接收客户端socket链接。

关键代码:

public void init() throws Exception {

............

// Initialize thread count defaults for acceptor

if (acceptorThreadCount == 0) {

acceptorThreadCount = 1;

}

..............

}

public void start() throws Exception {

.............

// Start acceptor threads

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

Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i);

acceptorThread.setPriority(threadPriority);

acceptorThread.setDaemon(daemon);

acceptorThread.start();

}

..............

}

线程:Acceptor代码如下/**

* Server socket acceptor thread.

*/

protected class Acceptor implements Runnable {

/**

* The background thread that listens for incoming TCP/IP connections and

* hands them off to an appropriate processor.

*/

public void run() {

// Loop until we receive a shutdown command

while (running) {

// Loop if endpoint is paused

while (paused) {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

// Ignore

}

}

// Accept the next incoming connection from the server socket

try {

Socket socket = serverSocketFactory.acceptSocket(serverSocket);

serverSocketFactory.initSocket(socket);

// Hand this socket off to an appropriate processor

if (!processSocket(socket)) {

// Close socket right away

try {

socket.close();

} catch (IOException e) {

// Ignore

}

}

}catch ( IOException x ) {

if ( running ) log.error(sm.getString("endpoint.accept.fail"), x);

} catch (Throwable t) {

log.error(sm.getString("endpoint.accept.fail"), t);

}

// The processor will recycle itself when it finishes

}

}

}

2:采用线程池技术处理和客户端的socket通信

tomcat默认的线程池(WorkStack)是一个数组模拟的栈,默认的大小是200.

代码如下:

/**

* Maximum amount of worker threads.

*/

protected int maxThreads = 200;

................

workers = new WorkerStack(maxThreads);

.................

public class WorkerStack {

protected Worker[] workers = null;

protected int end = 0;

public WorkerStack(int size) {

workers = new Worker[size];

}

/**

* Put the object into the queue. If the queue is full (for example if

* the queue has been reduced in size) the object will be dropped.

*

* @param object the object to be appended to the queue (first

* element).

*/

public void push(Worker worker) {

if (end < workers.length) {

workers[end++] = worker;

} else {

curThreads--;

}

}

/**

* Get the first object out of the queue. Return null if the queue

* is empty.

*/

public Worker pop() {

if (end > 0) {

return workers[--end];

}

return null;

}

/**

* Get the first object out of the queue, Return null if the queue

* is empty.

*/

public Worker peek() {

return workers[end];

}

/**

* Is the queue empty?

*/

public boolean isEmpty() {

return (end == 0);

}

/**

* How many elements are there in this queue?

*/

public int size() {

return (end);

}

/**

* Resize the queue. If there are too many objects in the queue for the

* new size, drop the excess.

*

* @param newSize

*/

public void resize(int newSize) {

Worker[] newWorkers = new Worker[newSize];

int len = workers.length;

if (newSize < len) {

len = newSize;

}

System.arraycopy(workers, 0, newWorkers, 0, len);

workers = newWorkers;

}

}

3:每当接收线程接收到客户端链接时,就从线程池中取出一个工作线程(Work)来处理socket通信。

关键代码如下:

/**

* Process given socket.

*/

protected boolean processSocket(Socket socket) {

try {

if (executor == null) {

getWorkerThread().assign(socket);

} else {

executor.execute(new SocketProcessor(socket));

}

} catch (Throwable t) {

// This means we got an OOM or similar creating a thread, or that

// the pool and its queue are full

log.error(sm.getString("endpoint.process.fail"), t);

return false;

}

return true;

}

/**

* 当没有空闲的工作线程时,当前线程阻塞,直到线程池//workers.size()>0,

*/

protected Worker getWorkerThread() {

// Allocate a new worker thread

synchronized (workers) {

Worker workerThread;

while ((workerThread = createWorkerThread()) == null) {

try {

workers.wait();

} catch (InterruptedException e) {

// Ignore

}

}

return workerThread;

}

}

protected Worker createWorkerThread() {

synchronized (workers) {

if (workers.size() > 0) {

curThreadsBusy++;

return workers.pop();

}

if ((maxThreads > 0) && (curThreads < maxThreads)) {

curThreadsBusy++;

if (curThreadsBusy == maxThreads) {

log.info(sm.getString("endpoint.info.maxThreads",

Integer.toString(maxThreads), address,

Integer.toString(port)));

}

return (newWorkerThread());

} else {

//从此处代码可以看出,如何我们修改server.xml文件connector的maxThreads属性为负数,则线程数可能会一直增加。

if (maxThreads < 0) {

curThreadsBusy++;

return (newWorkerThread());

} else {

return (null);

}

}

}

}

客户/**

* 创建并启动一个新的Daemon工作线程,等待处理客户端socket对象。

*/

protected Worker newWorkerThread() {

Worker workerThread = new Worker();

workerThread.start();

return (workerThread);

}

4:Work线程的代码如下protected class Worker implements Runnable {

protected Thread thread = null;

//available 来协调assign方法和await方法的调用次序。

protected boolean available = false;

protected Socket socket = null;

/**

* Process an incoming TCP/IP connection on the specified socket. Any

* exception that occurs during processing must be logged and swallowed.

* NOTE: This method is called from our Connector's thread. We

* must assign it to our own thread so that multiple simultaneous

* requests can be handled.

*

* @param socket TCP socket to process

*/

synchronized void assign(Socket socket) {

// Wait for the Processor to get the previous Socket

while (available) {

try {

wait();

} catch (InterruptedException e) {

}

}

// Store the newly available Socket and notify our thread

this.socket = socket;

available = true;

notifyAll();

}

/**

* Await a newly assigned Socket from our Connector, or null

* if we are supposed to shut down.

*/

private synchronized Socket await() {

// Wait for the Connector to provide a new Socket

while (!available) {

try {

wait();

} catch (InterruptedException e) {

}

}

// Notify the Connector that we have received this Socket

Socket socket = this.socket;

available = false;

notifyAll();

return (socket);

}

/**

* The background thread that listens for incoming TCP/IP connections and

* hands them off to an appropriate processor.

*/

public void run() {

// Process requests until we receive a shutdown signal

while (running) {

// Wait for the next socket to be assigned

Socket socket = await();

if (socket == null)

continue;

// Process the request from this socket

if (!setSocketOptions(socket) || !handler.process(socket)) {

// Close socket

try {

socket.close();

} catch (IOException e) {

}

}

// Finish up this request

socket = null;

recycleWorkerThread(this);

}

}

/**

* Start the background processing thread.

*/

public void start() {

thread = new Thread(this);

thread.setName(getName() + "-" + (++curThreads));

//是守护线程

thread.setDaemon(true);

thread.start();

}

}

5:工作线程的回收protected void recycleWorkerThread(Worker workerThread) {

synchronized (workers) {

workers.push(workerThread);

curThreadsBusy--;

workers.notify();

}

}

总结:从以上代码可以看出,默认线程池的最多能容纳200个工作线程,每个回收的线程都是阻塞的守护线程,当需要时可以直接拿来使用,不需要额外调用start()方法.仔细阅读该类的代码对我们实现socket通讯的服务端代码有一定的启示作用,完全可以在我们需要的时候重用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值