tomcat如何增大并发_看Tomcat如何进行并发编程

本文首发于微信公众号「Tomcat那些事儿」。

前面几篇文章,分别介绍和并发的生活化的概念以及与之对应的Java语言中的实现。

这一篇,我们来看看,对于这些概念,Tomcat内部是如何实践的,以及Tomcat容器内是如何使用并发的。

首先是最常用的synchronized

在容器的启动流程中,会从Server开始一直向到各个下层容器进行启动,下面的代码是Server找到配置的Service,进行遍历启动

private final Object servicesLock = new Object();

// Start our defined Services

synchronized(servicesLock) {

for (int i = 0; i < services.length; i++) {

services[i].start();

}

}

其次,是锁范围的减小

service的启动过程,其实是这样的protected void startInternal() throws LifecycleException {

// Start our defined Container first

if (container != null) {

synchronized(container) {

container.start();

}

}

synchronized(executors) {

for (Executor executor: executors) {

executor.start();

}

}

}

上面的代码,我们看到,并不是整个方法进行加锁,而是对于各个容器内组件的启动进行分别加锁。这种对于锁作用范围和持有时间的缩小,可以降低锁竞争,提升可伸缩性。当然,如果说所有的内容都分别加锁反而会影响性能。感兴趣的朋友可以阅读Java并发编程实战的性能与可伸缩性一章,了解更多内容。

用线程池启动容器内组件

// Start our child containers, if any

Container children[] = findChildren();

List> results = new ArrayList<>();

for (int i = 0; i < children.length; i++) {

results.add(startStopExecutor.submit(new StartChild(children[i])));

}

boolean fail = false;

for (Future result : results) {

try {

result.get();

} catch (Exception e) {

}}

各个容器获取到其子组件后,将其组装成一个任务,提交到任务执行线程池中。任务的执行结果,在通过其Future对象获取。

通过Callable封装带返回值的任务

private static class StartChild implements Callable {

private Container child;

public StartChild(Container child) {

this.child = child;

}

public Void call() throws LifecycleException {

child.start();

return null;

} }

由于组件的启动并不需要返回值,此处使用Void类型,可以在实际使用过程中换成具体的值返回具体的结果。在全部任务执行完成后,从Future中get返回值。

Volatile的使用private volatileboolean close = false;

// Time to terminate?

if (close) {

timeout(0, false);

try {

selector.close();

} catch (IOException ioe) {

}

通过使用volatile值,来保证多线程环境中关闭标识的可见性,从而能正确的在标识改变后退出特定逻辑。

wait/notify的使用

在前面的概念中,我们提到使用wait/notify的时候,一定要在拿到锁的情况下进行。Tomcat在进行Servlet实例allocate和deallocate的时候,会使用到这两个操作。synchronized (instancePool) {

while (countAllocated.get() >= nInstances) {

if (nInstances < maxInstances) {

instancePool.push(loadServlet());

nInstances++;

} else {

instancePool.wait();

}

}

卸载的时候,代码是这样的synchronized (instancePool){

countAllocated.decrementAndGet();

instancePool.push(servlet);

instancePool.notify();

}

两种情况都是先拿到锁再进行的。

当然,Tomcat中也有许多对JDK并发包内组件的使用,像下面这个对于CountDownLatch的使用

private volatile CountDownLatchstopLatch = null;

stopLatch = new CountDownLatch(pollerThreadCount); // 在Endpoint进行bind操作时,设置相应poller数量的CountDownLatch

// 在处理destory时,进行countDown操作,后续的关闭操作,会根据stopLatch的数据进行等待操作。

stopLatch.countDown();

以上,是Tomcat内部并发技术的使用方式,对于并发包内组件的使用这一部分,后面具体介绍相关内容时再细说。

相关阅读

猜你喜欢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值