您好,登錄后才能下訂單哦!
這篇文章主要講解了“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<Future<Void>> results = new ArrayList<>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
boolean fail = false;
for (Future<Void> result : results) {
try {
result.get();
} catch (Exception e) {
}}
各個容器獲取到其子組件后,將其組裝成一個任務,提交到任務執行線程池中。任務的執行結果,在通過其Future對象獲取。
通過Callable封裝帶返回值的任務
private static class StartChild implements Callable<Void> {
private Container child;
public StartChild(Container child) {
this.child = child;
}
public Void call() throws LifecycleException {
child.start();
return null;
} }
由于組件的啟動并不需要返回值,此處使用Void類型,可以在實際使用過程中換成具體的值返回具體的結果。在全部任務執行完成后,從Future中get返回值。
Volatile的使用
private volatile boolean 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 CountDownLatch stopLatch = null;
stopLatch = new CountDownLatch(pollerThreadCount); // 在Endpoint進行bind操作時,設置相應poller數量的CountDownLatch
// 在處理destory時,進行countDown操作,后續的關閉操作,會根據stopLatch的數據進行等待操作。
stopLatch.countDown();
感謝各位的閱讀,以上就是“Tomcat如何進行并發編程”的內容了,經過本文的學習后,相信大家對Tomcat如何進行并發編程這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。