多線程使用的主要目的在于:1、吞吐量:你做WEB,容器幫你做了多線程,但是他只能幫你做請求層面的。簡單的說,可能就是一個請求一個線程。或多個請求一個線程。如果是單線程,那同時只能處理一個用戶的請求。2、伸縮性:也就是說,你可以通過增加CPU核數來提升性能。如果是單線程,那程序執行到死也就利用了單核,肯定沒辦法通過增加CPU核數來提升性能。
鑒于是做WEB的,第1點可能你幾乎不涉及。那這里我就講第二點吧。fileName2Data=newHashMap(); privatevoidprocessFile3(StringfName){ Stringdata=fileName2Data.get(fName); if(data==null){ data=readFromFile(fName);//耗時28ms fileName2Data.put(fName,data); } //processwithdata } }
看起來好像還不錯,建立一個文件名和文件數據的映射。如果讀取一個map中已經存在的數據,那么就不不用讀取文件了。
可是問題在于,Servlet是并發,上面會導致一個很嚴重的問題,死循環。因為,HashMap在并發修改的時候,可能是導致循環鏈表的構成!!!(具體你可以自行閱讀HashMap源碼)如果你沒接觸過多線程,可能到時候發現服務器沒請求也巨卡,也不知道什么情況!
好的,那就用ConcurrentHashMap,正如他的名字一樣,他是一個線程安全的HashMap,這樣能輕松解決問題。fileName2Data=newConcurrentHashMap(); privatevoidprocessFile3(StringfName){ Stringdata=fileName2Data.get(fName); if(data==null){ data=readFromFile(fName);//耗時28ms fileName2Data.put(fName,data); } //processwithdata } }
這樣真的解決問題了嗎,這樣雖然只要有用戶訪問過文件a,那另一個用戶想訪問文件a,也會從fileName2Data中拿數據,然后也不會引起死循環。最新 Java 面試題出爐!分享給你。
可是,如果你覺得這樣就已經完了,那你把多線程也想的太簡單了,騷年!你會發現,1000個用戶首次訪問同一個文件的時候,居然讀取了1000次文件(這是最極端的,可能只有幾百)。What the ***in hell!!!
難道代碼錯了嗎,難道我就這樣過我的一生!
好好分析下。Servlet是多線程的,那么fileName2Data=newConcurrentHashMap(); privatevoidprocessFile3(StringfName){ Stringdata=fileName2Data.get(fName); //“偶然”--1000個線程同時到這里,同時發現data為null if(data==null){ data=readFromFile(fName);//耗時28ms fileName2Data.put(fName,data); } //processwithdata } }
上面注釋的“偶然”,這是完全有可能的,因此,這樣做還是有問題。
因此,可以自己簡單的封裝一個任務來處理。fileName2Data=newConcurrentHashMap(); privatestaticExecutorServiceexec=Executors.newCacheThreadPool(); privatevoidprocessFile3(StringfName){ FutureTaskdata=fileName2Data.get(fName); //“偶然”--1000個線程同時到這里,同時發現data為null if(data==null){ data=newFutureTask(fName); FutureTaskold=fileName2Data.putIfAbsent(fName,data); if(old==null){ data=old; }else{ exec.execute(data); } } Stringd=data.get(); //processwithdata } privateFutureTasknewFutureTask(finalStringfile){ returnnewFutureTask(newCallable(){ publicStringcall(){ returnreadFromFile(file); } privateStringreadFromFile(Stringfile){return"";} } } }
以上所有代碼都是直接在bbs打出來的,不保證可以直接運行。
多線程最多的場景:web服務器本身;各種專用服務器(如游戲服務器);
舉個簡單的例子:
假設有個請求,這個請求服務端的處理需要執行3個很緩慢的IO操作(比如數據庫查詢或文件查詢),那么正常的順序可能是(括號里面代表執行時間):- 讀取文件1 (10ms)
- 處理1的數據(1ms)
- 讀取文件2 (10ms)
- 處理2的數據(1ms)
- 讀取文件3 (10ms)
- 處理3的數據(1ms)
- 整合1、2、3的數據結果 (1ms)
- 讀取文件1 (1ms)
- 處理1的數據(1ms)
- 讀取文件2 (1ms)
- 處理2的數據(1ms)
- 讀取文件3 (28ms)
- 處理3的數據(1ms)
- 整合1、2、3的數據結果 (1ms)
偽代碼:
publicclassMyServletextendsServlet{ privatestaticMap
publicclassMyServletextendsServlet{ privatestaticConcurrentHashMap
publicclassMyServletextendsServlet{ privatestaticConcurrentHashMap
publicclassMyServletextendsServlet{ privatestaticConcurrentHashMap
審核編輯 :李倩
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
服務器
+關注
關注
12文章
9237瀏覽量
85666 -
JAVA
+關注
關注
19文章
2972瀏覽量
104866 -
多線程
+關注
關注
0文章
278瀏覽量
20021
原文標題:面試官:公司項目中Java的多線程一般用在哪些場景?
文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
多線程編程之一: 問題提出
:lpThreadAttributes:指向一個 SECURITY_ATTRIBUTES 結構的指針,該結構決定了線程的安全屬性,一般置為 NULL; dwStackSize:指定了線程
發表于 10-22 11:41
Java一直獨得恩寵的秘訣
Java中沒有指針,這樣就沒有辦法直接訪問內存了。另外Java也不容易出現內存泄露。而且Java確實有很多企業在用,都是用在大項目上。這就意
發表于 09-28 14:24
java多線程編程實例 (源程序)
java多線程編程實例
import java.awt.*;import javax.swing.*;
public class CompMover extends Object { 
發表于 10-22 11:48
?0次下載
java多線程設計模式_結城浩
《JAVA多線程設計模式》通過淺顯易懂的文字與實例來介紹JAVA線程相關的設計模式概念,并且通過實際的JAVA程序范例和UML圖示來一一解說
發表于 01-05 16:15
?0次下載
Java多線程總結之Queue
在Java多線程應用中,隊列的使用率很高,多數生產消費模型的首選數據結構就是隊列。Java提供的線程安全的Queue可以分為 阻塞隊列和非阻塞隊列 ,其中阻塞隊列的典型例子
發表于 11-28 16:14
?3323次閱讀
滌綸電容一般用在哪里?
二者是有區別的!滌綸電容又叫聚酯電容符號為CL,電容量一般40p--4μ, 額定電壓63--630V,主要特點體積小容量大耐熱耐濕但穩定性差一般應用在對穩定性和損耗要求不高的低頻電路。
發表于 11-13 09:51
?4252次閱讀
Java多線程永動任務 多線程異步任務項目解讀
, 這個示例的原型是公司自研的多線程異步任務項目 ,我把里面涉及到多線程的代碼抽離出來,然后進行一定的改造。 里面涉及的知識點非常多,特別適
多線程編程可以應用在哪里?C++多線程詳解
多線程并發指的是在同一個進程中執行多個線程。 優點: 有操作系統相關知識的應該知道,線程是輕量級的進程,每個線程可以獨立的運行不同的指令序列
發表于 04-13 10:10
?695次閱讀
紐扣型超級電容器一般是用在哪里?
紐扣型超級電容器一般是用在哪里?即便是同一種類型的產品,其型號、規格以及作用都是不同的。所以,大家在選擇產品的時候,也要從細節方面來考慮。紐扣型超級電容器在市場上是很常見的,它被應用在
評論