当前位置: 首页 > wzjs >正文

网站建设策划方案品牌策略怎么写

网站建设策划方案,品牌策略怎么写,企业管理咨询经营范围,网站建设报价 东莞如果大家觉得文章有错误内容,欢迎留言或者私信讨论~ 个人学习笔记版 上一篇文章我们了解了组成 Tomcat NioEndpoint 组件的各个部分以及它们的作用,今天我们的目标是攻略这些组件是如何在项目中被应用的,让我们开始吧。 前引 通过之前的学习…

如果大家觉得文章有错误内容,欢迎留言或者私信讨论~
个人学习笔记版

  上一篇文章我们了解了组成 Tomcat NioEndpoint 组件的各个部分以及它们的作用,今天我们的目标是攻略这些组件是如何在项目中被应用的,让我们开始吧。

前引

  通过之前的学习我们知道,NioEndpoint 组件负责 I/O 操作,也就是连接器的一部分,那么我们来到 NioEndpoint 源代码处,可以看到方法 startInternal,是不是联想到了什么?是的,Tomcat 通过 Lifecycle 来进行组件的生命周期管理,通过组合模式,只要最上层的父类组件创建、启动(调用start方法),其子类也会随之创建、启动。另外为了处理冗余代码,Tomcat 利用模板方法编写了 LifecycleBase 类,相对的,子类的启动方法也就变成了startInternal

在这里插入图片描述

  回顾完 Tomcat 的启动设计之后,我们来到 AbstractEndpoint,在该类里我们就可以找到 LimitLatch、Acceptor、Poller 等组件的创建实现。

public abstract class AbstractEndpoint<S,U> {public final void start() throws Exception {if (bindState == BindState.UNBOUND) {// 绑定监听的端口bindWithCleanup();bindState = BindState.BOUND_ON_START;}// 这里构建了 LimitLatch、Poller、Acceptor...startInternal();}
}

绑定监听端口

  作为连接器,我们需要通过指定的端口接受信息。通过上面的bindWithCleanup方法我们一路来到NioEndpoint#bind 方法,看到:

 @Override
public void bind() throws Exception {initServerSocket();// 忽略不必要代码
}protected void initServerSocket() throws Exception {if (getUseInheritedChannel()) {// 忽略不必要代码} else {// 经典的 java nio 写法 serverSock = ServerSocketChannel.open();socketProperties.setProperties(serverSock.socket());InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());serverSock.socket().bind(addr,getAcceptCount());}serverSock.configureBlocking(true); //mimic APR behavior
}

  bind 方法是我们需要注意的。第二个参数表示操作系统的等待队列长度,上一篇文章提到,当应用层面的连接数到达最大值时,操作系统可以继续接收连接,那么操作系统能继续接收的最大连接数就是这个队列长度,可以通过 acceptCount 参数配置,默认是 100。

public abstract class AbstractEndpoint<S,U> {private int acceptCount = 100;
}

  回AbstractEndpoint#startInternal ctrl + 鼠标右键直接来到 NioEndpoint 的实现,我们就可以看到各个组件在这里被创建、初始化与启动:

 @Override
public void startInternal() throws Exception {if (!running) {// 忽略不必要代码// Create worker collectionif (getExecutor() == null) {createExecutor();}initializeConnectionLatch();// Start poller threadpoller = new Poller();Thread pollerThread = new Thread(poller, getName() + "-Poller");pollerThread.setPriority(threadPriority);pollerThread.setDaemon(true);pollerThread.start();startAcceptorThread();}
}

  让我们再通过该图回忆一下个组件的功能:
在这里插入图片描述

LimitLatch

  LimitLatch 的创建就是简单的 new 操作,并且默认的最大连接数是 8*1024

public abstract class AbstractEndpoint<S,U> {protected LimitLatch initializeConnectionLatch() {if (maxConnections==-1) {return null;}if (connectionLimitLatch==null) {connectionLimitLatch = new LimitLatch(getMaxConnections());}return connectionLimitLatch;}
}public class LimitLatch {public LimitLatch(long limit) {this.limit = limit;this.count = new AtomicLong(0);this.sync = new Sync();}
}

  LimitLatch 内部定义了内部类 Sync,而 Sync 扩展了 AQS(在 Java API 文档中标明 AQS 的子类应定义为非公共内部帮助类,用于实现其封闭类的同步属性)。AQS 是分为独占和共享两种模式,当以独占模式获取时,其他线程尝试的获取无法成功。多个线程获取共享模式可能(但不一定)成功,LimitLatch 的内部类 Sync 实现的抽象方法则属于共享模式。

  并且 AQS 本身是具备先进先出(FIFO)等待队列的阻塞锁和相关同步器,但是 LimitLatch 中的 Sync 则依赖自己的 AtomicLong count 作为信号量来进行判断。

  用户线程通过调用 LimitLatch 的 countUpOrAwait 方法来拿到锁,如果暂时无法获取,这个线程会被阻塞到 AQS 的队列中。那 AQS 怎么知道是阻塞还是不阻塞用户线程呢?其实这是由 AQS 的使用者来决定的,也就是内部类 Sync 来决定的,因为 Sync 类重写了 AQS 的 tryAcquireShared() 方法。它的实现逻辑是如果当前连接数 count 小于 limit,线程能获取锁,返回 1,否则返回 -1。

AQS

  一般而言要使用 AQS 作为同步类的基础,就需要重写以下几个方法:

// 独占
tryAcquire(int)
tryRelease(int)
// 共享
tryAcquireShared(int)
tryReleaseShared(int)
isHeldExclusively()
// 默认调用都是抛出 UnsupportedOperationException 异常

  官方推荐实现这些方法必须是内部线程安全的,代码逻辑简短且不会阻塞的。AQS 中的其他方法被定义为了 final,不支持重写。以下是 AQS 实现的示例:

public class Mutex implements Lock, Serializable {private class Sync extends AbstractQueuedSynchronizer {@Overrideprotected boolean isHeldExclusively() {return getState() == 1;}@Overrideprotected boolean tryAcquire(int acquires) {assert acquires == 1; // Otherwise unusedif (compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}@Overrideprotected boolean tryRelease(int releases) {assert releases == 1; // Otherwise unusedif (getState() == 0) throw new IllegalMonitorStateException();setExclusiveOwnerThread(null);setState(0);return true;}Condition newCondition() {return new ConditionObject();}// Deserializes properlyprivate void readObject(ObjectInputStream s)throws IOException, ClassNotFoundException {s.defaultReadObject();setState(0); // reset to unlocked state}}// The sync object does all the hard work. We just forward to it.private final Sync sync = new Sync();@Overridepublic void lock() {sync.acquire(1);}@Overridepublic void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}@Overridepublic boolean tryLock() {return sync.tryAcquire(1);}@Overridepublic boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {return sync.tryAcquireNanos(1, unit.toNanos(timeout));}@Overridepublic void unlock() {sync.release(1);}@Overridepublic Condition newCondition() {return sync.newCondition();}
}

Acceptor

  看完 LimitLatch 的源码,我们再看startAcceptorThread()。Acceptor 跑在一个独立的线程里,它在一个死循环里内调用 accept 方法来接受新连接,一旦有新连接请求的到来,accpet 方法返回一个 Channel 对象,接着把 Channel 对象交给 Poller 去处理。

  Acceptor 的创建流程非常简单:

 protected void startAcceptorThread() {acceptor = new Acceptor<>(this);String threadName = getName() + "-Acceptor";acceptor.setThreadName(threadName);Thread t = new Thread(acceptor, threadName);t.setPriority(getAcceptorThreadPriority());t.setDaemon(getDaemon());t.start();}

  Accpetor run() 的方法可以总结为通过观测 endpoint 或者 Tomcat 的状态以及利用 LimitLatch 的countUpOrAwaitConnection 方法来确定是否要接受 SocketChannel:

public class Acceptor<U> implements Runnable {@Overridepublic void run() {// 忽略 感兴趣的同学可以自己去看// 如果达到最大连接数 等待endpoint.countUpOrAwaitConnection();if (endpoint.isPaused()) {continue;}// 接受下一次服务器传入的连接socket = endpoint.serverSocketAccept();// 给拿到的 SocketChannel 设置对应的处理器// 如果失败就关闭它if (!endpoint.setSocketOptions(socket)) {endpoint.closeSocket(socket);}}
}public class NioEndpoint extends AbstractJsseEndpoint<NioChannel,SocketChannel> {@Overrideprotected SocketChannel serverSocketAccept() throws Exception {SocketChannel result = serverSock.accept();// 忽略不必要代码return result;}@Overrideprotected boolean setSocketOptions(SocketChannel socket) {NioSocketWrapper socketWrapper = null;try {// 就是通过 NioSocketWrapper 类将 channel 与对应的 handler、poller 绑定在一起NioChannel channel = null;if (nioChannels != null) {channel = nioChannels.pop();}if (channel == null) {SocketBufferHandler bufhandler = new SocketBufferHandler(socketProperties.getAppReadBufSize(),socketProperties.getAppWriteBufSize(),socketProperties.getDirectBuffer());if (isSSLEnabled()) {channel = new SecureNioChannel(bufhandler, this);} else {channel = new NioChannel(bufhandler);}}NioSocketWrapper newWrapper = new NioSocketWrapper(channel, this);channel.reset(socket, newWrapper);connections.put(socket, newWrapper);socketWrapper = newWrapper;// 忽略不必要代码poller.register(socketWrapper);} catch(Throwable t) {// 忽略不必要代码}}
}

Poller 与 SocketProcessor

  Poller 也是跑在一个单独的线程,本质上一个 selector,它的创建过程如下:

// Start poller thread
poller = new Poller();
Thread pollerThread = new Thread(poller, getName() + "-Poller");
pollerThread.setPriority(threadPriority);
pollerThread.setDaemon(true);
pollerThread.start();

  Poller 是 NioEndpoint 的一个内部类,它内部维护了一个 selector、和一个 PollerEvent 类型的 channel 数组。前者就是我提到的本质上是一个 selector,可以看到它的构造函数:

public Poller() throws IOException {this.selector = Selector.open();
}

  因为 Poller 本身也是一个 Runnable 实现类,所以对于后者,它在一个死循环里不断检测 Channel 的数据就绪状态,一旦有 Channel 可读,就生成一个 SocketProcessor 任务对象扔给 Executor 去处理。

  我们知道,Poller 会创建 SocketProcessor 任务类交给线程池处理,而 SocketProcessor 实现了 Runnable 接口,用来定义 Executor 中线程所执行的任务,主要就是调用 Http11Processor 组件来处理请求。Http11Processor 读取 Channel 的数据来生成 ServletRequest 对象,这里请你注意:

  Http11Processor 并不是直接读取 Channel 的。这是因为 Tomcat 支持同步非阻塞 I/O 模型和异步 I/O 模型,在 Java API 中,相应的 Channel 类也是不一样的,比如有 AsynchronousSocketChannel 和 SocketChannel,为了对 Http11Processor 屏蔽这些差异,Tomcat 设计了一个包装类叫作 SocketWrapper,Http11Processor 只调用 SocketWrapper 的方法去读写数据。

Executor

  后续会专门讲解 Tomcat 的 Executor。

http://www.dtcms.com/wzjs/137773.html

相关文章:

  • 张掖高端网站建设公司宣传软文范例
  • 网站设计行业资讯武汉seo霸屏
  • 西安网站建设 美科动西安百度关键词推广
  • ubuntu 建网站宁波seo怎么做引流推广
  • 卡盟怎么做网站疫情放开最新消息今天
  • 个人备案域名可以做哪些网站吗关键词免费下载
  • 安卓做视频网站好南宁seo平台标准
  • 计算机课程网站建设实训报告总结丁香人才网官方网站
  • 安阳网站建设设计优化网站排名推广
  • 网站开发登录要做哪些验证网络营销的常用方法
  • 免费网站导航建设google关键词排名
  • 美女做游戏广告视频网站有哪些搜索词排行榜
  • 本地网站建设教程xampp厦门人才网官方网站
  • wordpress 图文插件优化关键词排名软件
  • 临沂网站建设公司全国网站推广及seo方案
  • 做钢结构网站有哪些北京网站建设专业公司
  • 杭州建设招标网简述影响关键词优化的因素
  • 网站是什么样的杭州seo技术
  • 怎样才能建一个网站口碑营销的前提及好处有哪些?
  • 南宁 网站设计大连网站排名推广
  • 长春高端网站建设网站营销策划公司
  • 上海品牌网站制作优化什么建立生育支持政策体系
  • 新乡市做网站直销系统网站蚁坊软件舆情监测系统
  • 做平台的网站有哪些内容如何让百度收录自己的网站
  • 网站制作文案广州seo优化公司
  • 国外ps网站网站怎么找
  • 市网站制作百度手机助手下载安装
  • 怎么搭建一个小程序沈阳关键字优化公司
  • 禄劝彝族苗族网站建设网络关键词
  • 网站分类主要有哪些西安网络推广优化培训