最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Tomcat使用線程池處理遠(yuǎn)程并發(fā)請(qǐng)求的方法

 更新時(shí)間:2020年12月25日 09:01:07   作者:Narule  
這篇文章主要介紹了Tomcat使用線程池處理遠(yuǎn)程并發(fā)請(qǐng)求的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

通過了解學(xué)習(xí)tomcat如何處理并發(fā)請(qǐng)求,了解到線程池,鎖,隊(duì)列,unsafe類,下面的主要代碼來自

java-jre:

sun.misc.Unsafe
java.util.concurrent.ThreadPoolExecutor
java.util.concurrent.ThreadPoolExecutor.Worker
java.util.concurrent.locks.AbstractQueuedSynchronizer
java.util.concurrent.locks.AbstractQueuedLongSynchronizer
java.util.concurrent.LinkedBlockingQueue

tomcat:

org.apache.tomcat.util.net.NioEndpoint
org.apache.tomcat.util.threads.ThreadPoolExecutor
org.apache.tomcat.util.threads.TaskThreadFactory
org.apache.tomcat.util.threads.TaskQueue

ThreadPoolExecutor

是一個(gè)線程池實(shí)現(xiàn)類,管理線程,減少線程開銷,可以用來提高任務(wù)執(zhí)行效率,

構(gòu)造方法中的參數(shù)有

public ThreadPoolExecutor(
 int corePoolSize,
 int maximumPoolSize,
 long keepAliveTime,
 TimeUnit unit,
 BlockingQueue<Runnable> workQueue,
 ThreadFactory threadFactory,
 RejectedExecutionHandler handler) {
 
}

corePoolSize 是核心線程數(shù)
maximumPoolSize 是最大線程數(shù)
keepAliveTime 非核心線程最大空閑時(shí)間(超過時(shí)間終止)
unit 時(shí)間單位
workQueue 隊(duì)列,當(dāng)任務(wù)過多時(shí),先存放在隊(duì)列
threadFactory 線程工廠,創(chuàng)建線程的工廠
handler 決絕策略,當(dāng)任務(wù)數(shù)過多,隊(duì)列不能再存放任務(wù)時(shí),該如何處理,由此對(duì)象去處理。這是個(gè)接口,你可以自定義處理方式

ThreadPoolExecutor在Tomcat中http請(qǐng)求的應(yīng)用

此線程池是tomcat用來在接收到遠(yuǎn)程請(qǐng)求后,將每次請(qǐng)求單獨(dú)作為一個(gè)任務(wù)去處理,每次調(diào)用execute(Runnable)

初始化

org.apache.tomcat.util.net.NioEndpoint

NioEndpoint初始化的時(shí)候,創(chuàng)建了線程池

public void createExecutor() {
 internalExecutor = true;
 TaskQueue taskqueue = new TaskQueue();
 //TaskQueue無界隊(duì)列,可以一直添加,因此handler 等同于無效
 TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
 executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
 taskqueue.setParent( (ThreadPoolExecutor) executor);
 }

在線程池創(chuàng)建時(shí),調(diào)用prestartAllCoreThreads(), 初始化核心工作線程worker,并啟動(dòng)

public int prestartAllCoreThreads() {
 int n = 0;
 while (addWorker(null, true))
  ++n;
 return n;
 }

當(dāng)addWorker 數(shù)量等于corePoolSize時(shí),addWorker(null,ture)會(huì)返回false,停止worker工作線程的創(chuàng)建

提交任務(wù)到隊(duì)列

每次客戶端過來請(qǐng)求(http),就會(huì)提交一次處理任務(wù),

worker 從隊(duì)列中獲取任務(wù)運(yùn)行,下面是任務(wù)放入隊(duì)列的邏輯代碼

ThreadPoolExecutor.execute(Runnable) 提交任務(wù):

public void execute(Runnable command) {
 if (command == null)
  throw new NullPointerException();
 
 int c = ctl.get();
 	// worker數(shù) 是否小于 核心線程數(shù) tomcat中初始化后,一般不滿足第一個(gè)條件,不會(huì)addWorker
 if (workerCountOf(c) < corePoolSize) {
  if (addWorker(command, true))
  return;
  c = ctl.get();
 }
 	// workQueue.offer(command),將任務(wù)添加到隊(duì)列,
 if (isRunning(c) && workQueue.offer(command)) {
  int recheck = ctl.get();
  if (! isRunning(recheck) && remove(command))
  reject(command);
  else if (workerCountOf(recheck) == 0)
  addWorker(null, false);
 }
 else if (!addWorker(command, false))
  reject(command);
 }

workQueue.offer(command) 完成了任務(wù)的提交(在tomcat處理遠(yuǎn)程http請(qǐng)求時(shí))。

workQueue.offer

TaskQueue 是 BlockingQueue 具體實(shí)現(xiàn)類,workQueue.offer(command)實(shí)際代碼:

public boolean offer(E e) {
 if (e == null) throw new NullPointerException();
 final AtomicInteger count = this.count;
 if (count.get() == capacity)
 return false;
 int c = -1;
 Node<E> node = new Node<E>(e);
 final ReentrantLock putLock = this.putLock;
 putLock.lock();
 try {
 if (count.get() < capacity) {
  enqueue(node); //此處將任務(wù)添加到隊(duì)列
  c = count.getAndIncrement();
  if (c + 1 < capacity)
  notFull.signal();
 }
 } finally {
 putLock.unlock();
 }
 if (c == 0)
 signalNotEmpty();
 return c >= 0;
}

// 添加任務(wù)到隊(duì)列
/**
 * Links node at end of queue.
 *
 * @param node the node
 */
private void enqueue(Node<E> node) {
 // assert putLock.isHeldByCurrentThread();
 // assert last.next == null;
 last = last.next = node; //鏈表結(jié)構(gòu) last.next = node; last = node
}

之后是worker的工作,worker在run方法中通過去getTask()獲取此處提交的任務(wù),并執(zhí)行完成任務(wù)。

線程池如何處理新提交的任務(wù)

添加worker之后,提交任務(wù),因?yàn)閣orker數(shù)量達(dá)到corePoolSize,任務(wù)都會(huì)將放入隊(duì)列,而worker的run方法則是循環(huán)獲取隊(duì)列中的任務(wù)(不為空時(shí)),

worker run方法:

/** Delegates main run loop to outer runWorker */
 public void run() {
  runWorker(this);
 }

循環(huán)獲取隊(duì)列中的任務(wù)

runWorker(worker)方法 循環(huán)部分代碼:

final void runWorker(Worker w) {
 Thread wt = Thread.currentThread();
 Runnable task = w.firstTask;
 w.firstTask = null;
 w.unlock(); // allow interrupts
 boolean completedAbruptly = true;
 try {
  while (task != null || (task = getTask()) != null) { //循環(huán)獲取隊(duì)列中的任務(wù)
  w.lock(); // 上鎖
  try {
   // 運(yùn)行前處理
   beforeExecute(wt, task);
   // 隊(duì)列中的任務(wù)開始執(zhí)行
   task.run();
   // 運(yùn)行后處理
   afterExecute(task, thrown);
  } finally {
   task = null;
   w.completedTasks++;
   w.unlock(); // 釋放鎖
  }
  }
  completedAbruptly = false;
 } finally {
  processWorkerExit(w, completedAbruptly);
 }
 }

task.run()執(zhí)行任務(wù)

鎖運(yùn)用

ThreadPoolExecutor 使用鎖主要保證兩件事情,
1.給隊(duì)列添加任務(wù),保證其他線程不能操作隊(duì)列
2.獲取隊(duì)列的任務(wù),保證其他線程不能同時(shí)操作隊(duì)列

給隊(duì)列添加任務(wù)上鎖

public boolean offer(E e) {
 if (e == null) throw new NullPointerException();
 final AtomicInteger count = this.count;
 if (count.get() == capacity)
  return false;
 int c = -1;
 Node<E> node = new Node<E>(e);
 final ReentrantLock putLock = this.putLock;
 putLock.lock(); //上鎖
 try {
  if (count.get() < capacity) {
  enqueue(node);
  c = count.getAndIncrement();
  if (c + 1 < capacity)
   notFull.signal();
  }
 } finally {
  putLock.unlock(); //釋放鎖
 }
 if (c == 0)
  signalNotEmpty();
 return c >= 0;
 }

 

獲取隊(duì)列任務(wù)上鎖

private Runnable getTask() {
 boolean timedOut = false; // Did the last poll() time out?
		// ...省略
 for (;;) {
  try {
  Runnable r = timed ?
   workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
   workQueue.take(); //獲取隊(duì)列中一個(gè)任務(wù)
  if (r != null)
   return r;
  timedOut = true;
  } catch (InterruptedException retry) {
  timedOut = false;
  }
 }
 }
public E take() throws InterruptedException {
 E x;
 int c = -1;
 final AtomicInteger count = this.count;
 final ReentrantLock takeLock = this.takeLock;
 takeLock.lockInterruptibly(); // 上鎖
 try {
  while (count.get() == 0) {
  notEmpty.await(); //如果隊(duì)列中沒有任務(wù),等待
  }
  x = dequeue();
  c = count.getAndDecrement();
  if (c > 1)
  notEmpty.signal();
 } finally {
  takeLock.unlock(); // 釋放鎖
 }
 if (c == capacity)
  signalNotFull();
 return x;
 }

volatile

在并發(fā)場(chǎng)景這個(gè)關(guān)鍵字修飾成員變量很常見,

主要目的公共變量在被某一個(gè)線程修改時(shí),對(duì)其他線程可見(實(shí)時(shí))

sun.misc.Unsafe 高并發(fā)相關(guān)類

線程池使用中,有平凡用到Unsafe類,這個(gè)類在高并發(fā)中,能做一些原子CAS操作,鎖線程,釋放線程等。

sun.misc.Unsafe 類是底層類,openjdk源碼中有

原子操作數(shù)據(jù)

java.util.concurrent.locks.AbstractQueuedSynchronizer 類中就有保證原子操作的代碼

protected final boolean compareAndSetState(int expect, int update) {
 // See below for intrinsics setup to support this
 return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
 }

對(duì)應(yīng)Unsafe類的代碼:

//對(duì)應(yīng)的java底層,實(shí)際是native方法,對(duì)應(yīng)C++代碼
/**
* Atomically update Java variable to <tt>x</tt> if it is currently
* holding <tt>expected</tt>.
* @return <tt>true</tt> if successful
*/
public final native boolean compareAndSwapInt(Object o, long offset,
      int expected,
      int x);

方法的作用簡(jiǎn)單來說就是 更新一個(gè)值,保證原子性操作
當(dāng)你要操作一個(gè)對(duì)象o的一個(gè)成員變量offset時(shí),修改o.offset,
高并發(fā)下為保證準(zhǔn)確性,你在操作o.offset的時(shí)候,讀應(yīng)該是正確的值,并且中間不能被別的線程修改來保證高并發(fā)的環(huán)境數(shù)據(jù)操作有效。

即 expected 期望值與內(nèi)存中的值比較是一樣的expected == 內(nèi)存中的值 ,則更新值為 x,返回true代表修改成功

否則,期望值與內(nèi)存值不同,說明值被其他線程修改過,不能更新值為x,并返回false,告訴操作者此次原子性修改失敗。

阻塞和喚醒線程

public native void park(boolean isAbsolute, long time); //阻塞當(dāng)前線程

線程池的worker角色循環(huán)獲取隊(duì)列任務(wù),如果隊(duì)列中沒有任務(wù),worker.run 還是在等待的,不會(huì)退出線程,代碼中用了notEmpty.await() 中斷此worker線程,放入一個(gè)等待線程隊(duì)列(區(qū)別去任務(wù)隊(duì)列);當(dāng)有新任務(wù)需要時(shí),再notEmpty.signal()喚醒此線程

底層分別是
unsafe.park() 阻塞當(dāng)前線程
public native void park(boolean isAbsolute, long time);

unsafe.unpark() 喚醒線程
public native void unpark(Object thread);

這個(gè)操作是對(duì)應(yīng)的,阻塞時(shí),先將thread放入隊(duì)列,喚醒時(shí),從隊(duì)列拿出被阻塞的線程,unsafe.unpark(thread)喚醒指定線程。

java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject 類中

通過鏈表存放線程信息

// 添加一個(gè)阻塞線程
private Node addConditionWaiter() {
  Node t = lastWaiter;
  // If lastWaiter is cancelled, clean out.
  if (t != null && t.waitStatus != Node.CONDITION) {
  unlinkCancelledWaiters();
  t = lastWaiter;
  }
  Node node = new Node(Thread.currentThread(), Node.CONDITION);
  if (t == null)
  firstWaiter = node;
  else
  t.nextWaiter = node;
  lastWaiter = node; //將新阻塞的線程放到鏈表尾部
  return node;
 }

// 拿出一個(gè)被阻塞的線程
 public final void signal() {
  if (!isHeldExclusively())
  throw new IllegalMonitorStateException();
  Node first = firstWaiter; //鏈表中第一個(gè)阻塞的線程
  if (first != null)
  doSignal(first);
 }

// 拿到后,喚醒此線程
final boolean transferForSignal(Node node) {
  LockSupport.unpark(node.thread);
 return true;
 }
public static void unpark(Thread thread) {
 if (thread != null)
  UNSAFE.unpark(thread);
 }

到此這篇關(guān)于Tomcat使用線程池處理遠(yuǎn)程并發(fā)請(qǐng)求的方法的文章就介紹到這了,更多相關(guān)Tomcat線程池處理遠(yuǎn)程并發(fā)請(qǐng)求內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Tomcat HTTPS證書申請(qǐng)與部署的實(shí)現(xiàn)

    Tomcat HTTPS證書申請(qǐng)與部署的實(shí)現(xiàn)

    本文主要介紹了Tomcat HTTPS證書申請(qǐng)與部署的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 使用Tomcat服務(wù)器運(yùn)行sts時(shí)出現(xiàn)報(bào)錯(cuò)的解決辦法

    使用Tomcat服務(wù)器運(yùn)行sts時(shí)出現(xiàn)報(bào)錯(cuò)的解決辦法

    前幾天在運(yùn)行 Spring ToolSuite 時(shí)出現(xiàn)Starting Tomcat v8.5 Server at localhost' hasencountered a problem.的錯(cuò)誤,所以本文給大家介紹了解決這個(gè)錯(cuò)的方法,需要的朋友可以參考下
    2023-09-09
  • IDEA中的Tomcat中文亂碼問題

    IDEA中的Tomcat中文亂碼問題

    本文主要介紹了IDEA中的Tomcat中文亂碼問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 如何設(shè)置Tomcat的默認(rèn)端口(圖文)

    如何設(shè)置Tomcat的默認(rèn)端口(圖文)

    Tomcat安裝時(shí)默認(rèn)的端口設(shè)置的是8080,而http協(xié)議的默認(rèn)端口是80,所以測(cè)試Tomcat時(shí)需要輸入的網(wǎng)址為“http://localhost:8080”,若把Tomcat的端口設(shè)置為80,則直接輸入“http://localhost”就能顯示Tomcat默認(rèn)主頁,下面我們來分享下,方便需要的朋友
    2014-06-06
  • 解決tomcat在Debug模式下無法啟動(dòng)問題

    解決tomcat在Debug模式下無法啟動(dòng)問題

    這篇文章主要介紹了解決tomcat在Debug模式下無法啟動(dòng)問題,運(yùn)行環(huán)境在eclipse,JDK1.6,tomcat6.0上,具體問題解決方法大家參考下本文
    2018-02-02
  • Tomcat服務(wù)器配置https認(rèn)證(使用keytool生成證書)

    Tomcat服務(wù)器配置https認(rèn)證(使用keytool生成證書)

    本文主要介紹了Tomcat服務(wù)器配置https認(rèn)證,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • 關(guān)于Tomcat?結(jié)合Atomikos?實(shí)現(xiàn)JTA的方法

    關(guān)于Tomcat?結(jié)合Atomikos?實(shí)現(xiàn)JTA的方法

    Tomcat作為一款經(jīng)典的Web服務(wù)器,在開發(fā)、測(cè)試和生產(chǎn)環(huán)境中得到了廣泛的使用。但Tomcat畢竟不是Java EE服務(wù)器,因此在EJB,JTA方面并沒有提供支持。本文講述了Tomcat使用Atomikos實(shí)現(xiàn)JTA的一種方法,需要的朋友可以參考下
    2021-11-11
  • tomcat配置虛擬路徑的實(shí)現(xiàn)步驟

    tomcat配置虛擬路徑的實(shí)現(xiàn)步驟

    本文主要介紹了tomcat配置虛擬路徑的實(shí)現(xiàn)步驟,主要是在localhost文件中進(jìn)行配置,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • 基于tomcat配置文件server.xml詳解

    基于tomcat配置文件server.xml詳解

    下面小編就為大家?guī)硪黄趖omcat配置文件server.xml詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • 詳解tomcat 解決 POST請(qǐng)求傳參數(shù)過長(zhǎng)受限制的問題

    詳解tomcat 解決 POST請(qǐng)求傳參數(shù)過長(zhǎng)受限制的問題

    這篇文章主要介紹了詳解tomcat 解決 POST請(qǐng)求傳參數(shù)過長(zhǎng)受限制的問題,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08

最新評(píng)論

浦江县| 邵阳县| 大埔区| 青神县| 增城市| 永靖县| 营山县| 宜宾市| 大理市| 彩票| 光山县| 凤翔县| 黔东| 闽侯县| 滨海县| 开平市| 南江县| 乌海市| 谢通门县| 珲春市| 松溪县| 普兰县| 平远县| 井陉县| 洛宁县| 彭泽县| 大丰市| 望都县| 曲水县| 阳朔县| 宿州市| 万盛区| 临江市| 利津县| 吉木乃县| 辽宁省| 灵石县| 永清县| 岳普湖县| 封丘县| 建宁县|