① java多線程問題:多個線程訪問同一資源時如何保證線程之間訪問的順序性。
這個需要鎖,當a敲完時,加一把鎖,然後只能b解開,然後b敲完,加一把鎖,只能a解開,這樣他們就會這樣執行下去,其實這個原理在socket中有用到,你可以看看
② C++程序,兩個線程同時訪問一個容器,讀的時候同時往裡寫數據
只能說你不會用鎖,加鎖後寫的線程lock的時候就會等待,直到鎖可用;如果數據因為其他原因丟失就需要加緩存,將要寫的臨時寫到緩存中,建議讀寫鎖,都是讀不互斥,只有帶寫的互斥
③ 如果有2個用戶訪問一個jsp頁面,該頁面中的java程序片將被執行幾次
一個件jsp頁面同時被兩個用戶訪問時,其java程序片被執行兩次,運行在不同的線程中。
④ 新手求助,多個客戶同時訪問同一個JSP頁面時的線程
servlet是默認採用單實例,多線程的此判方式進行。只要webapp被發布到web容器中的時候,servlet只會在發布的時候實例化一次,servlet在其生命周期中只有在將項目給移除或伺服器stop的時候才會銷毀。
當請求到達時,Servlet容器通橋橋過調度線程(Dispatchaer Thread)調度它管理下的線程池中等待執行的線程(Worker Thread)給請求者;
出現不同的線程同一時間訪問同一個servlet的時候,servlet的對象只有一個,但是由於是tomcat支持多線程的原因,每個客戶端請求執行森消改的servlet中的函數都是在自己所支配的那一小段線程裡面執行了,也就是說兩個用戶都登陸,都訪問login方法,但是這是有用的是一個servlet但是局部的方法是放在不同的線程裡面的
最後請求結束,放回線程池,等到被調用
⑤ 在分時/多任務系統里,如果兩個進程同時訪問同一個文件
線程和進程都是現在電腦概念里比較時髦的用語,什麼是多線程,什麼是多進程?本文詳細的給您介紹一下,希望能增進您對當代電腦技術的了解,有不到之處,還往高手予以更正。進程(英語:Process,中國大陸譯作進程,台灣譯作行程)是計算機中已運行程序的實體。進程本身不會運行,是線程的容器。程序本身只是指令的集合,進程才是程序(那些指令)的真正運行。若干進程有可能與同一個程序相關系,且每個進程皆可以同步(循序)或不同步(平行)的方式獨立運行。進程為現今分時系統的基本運作單位 線程(英語:thread,台灣譯為運行緒),操作系統技術中的術語,是操作系統能夠進行運算調度的最小單位。它被包涵在進程之中,一條線程指的是進程中一個單一順序的控制流,一個進程中可以並發多個線程,每條線程並行執行不同的任務。在Unix System V及SunOS中也被稱為輕量進程(lightweight processes),但輕量進程更多指內核線程(kernel thread),而把用戶線程(user thread)稱為線程。 線程是獨立調度和分派的基本單位。線程可以操作系統內核調度的內核線程,如Win32 線程;由用戶進程自行調度的用戶線程,如Linux Portable Thread; 或者由內核與用戶進程,如Windows 7的線程,進行混合調度。 同一進程中的多條線程將共享該進程中的全部系統資源,如虛擬地址空間,文件描述符和信號處理等等。但同一進程中的多個線程有各自的調用棧(call stack),自己的寄存器環境(register context),自己的線程本地存儲(thread-local storage)。 一個進程可以有很多線程,每條線程並行執行不同的任務。 在多核或多CPU,或支持Hyper-threading的CPU上使用多線程程序設計的好處是顯而易見,即提高了程序的執行吞吐率。在單CPU單核的計算機上,使用多線程技術,也可以把進程中負責IO處理、人機交互而常備阻塞的部分與密集計算的部分分開來執行,編寫專門的workhorse線程執行密集計算,從而提高了程序的執行效率 進程是資源分配的最小單位,線程是CPU調度的最小單位。線程和進程的區別在於,子進程和父進程有不同的代碼和數據空間,而多個線程則共享數據空間,每個線程有自己的執行堆棧和程序計數器為其執行上下文.多線程主要是為了節約CPU時間,發揮利用,根據具體情況而定. 線程的運行中需要使用計算機的內存資源和CPU。 多進程: 進程是程序在計算機上的一次執行活動。當你運行一個程序,你就啟動了一個進程。顯然,程序是死的(靜態的),進程是活的(動態的)。進程可以分為系統進程和用戶進程。凡是用於完成操作系統的各種功能的進程就是系統進程,它們就是處於運行狀態下的操作系統本身;所有由用戶啟動的進程都是用戶進程。進程是操作系統進行資源分配的單位。 進程又被細化為線程,也就是一個進程下有多個能獨立運行的更小的單位。在同一個時間里,同一個計算機系統中如果允許兩個或兩個以上的進程處於運行狀態,這便是多任務。現代的操作系統幾乎都是多任務操作系統,能夠同時管理多個進程的運行。 多任務帶來的好處是明顯的,比如你可以邊聽mp3邊上網,與此同時甚至可以將下載的文檔列印出來,而這些任務之間絲毫不會相互干擾。那麼這里就涉及到並行的問題,俗話說,一心不能二用,這對計算機也一樣,原則上一個CPU只能分配給一個進程,以便運行這個進程。我們通常使用的計算機中只有一個CPU,也就是說只有一顆心,要讓它一心多用,同時運行多個進程,就必須使用並發技術。實現並發技術相當復雜,最容易理解的是「時間片輪轉進程調度演算法」,它的思想簡單介紹如下:在操作系統的管理下,所有正在運行的進程輪流使用CPU,每個進程允許佔用CPU的時間非常短(比如10毫秒),這樣用戶根本感覺不出來 CPU是在輪流為多個進程服務,就好象所有的進程都在不間斷地運行一樣。但實際上在任何一個時間內有且僅有一個進程佔有CPU。 如果一台計算機有多個CPU,情況就不同了,如果進程數小於CPU數,則不同的進程可以分配給不同的CPU來運行,這樣,多個進程就是真正同時運行的,這便是並行。但如果進程數大於CPU數,則仍然需要使用並發技術。 進行CPU分配是以線程為單位的,一個進程可能由多個線程組成,這時情況更加復雜,但簡單地說,有如下關系: 匯流排程數<= CPU數量:並行運行 匯流排程數> CPU數量:並發運行 並行運行的效率顯然高於並發運行,所以在多CPU的計算機中,多任務的效率比較高。但是,如果在多CPU計算機中只運行一個進程(線程),就不能發揮多CPU的優勢。 這里涉及到多任務操作系統的問題,多任務操作系統(如Windows)的基本原理是:操作系統將CPU的時間片分配給多個線程,每個線程在操作系統指定的時間片內完成(注意,這里的多個線程是分屬於不同進程的).操作系統不斷的從一個線程的執行切換到另一個線程的執行,如此往復,宏觀上看來,就好像是多個線程在一起執行.由於這多個線程分屬於不同的進程,因此在我們看來,就好像是多個進程在同時執行,這樣就實現了多任務 多線程:在計算機編程中,一個基本的概念就是同時對多個任務加以控制。許多程序設計問題都要求程序能夠停下手頭的工作,改為處理其他一些問題,再返回主進程。可以通過多種途徑達到這個目的。最開始的時候,那些掌握機器低級語言的程序員編寫一些「中斷服務常式」,主進程的暫停是通過硬體級的中斷實現的。盡管這是一種有用的方法,但編出的程序很難移植,由此造成了另一類的代價高昂問題。中斷對那些實時性很強的任務來說是很有必要的。但對於其他許多問題,只要求將問題劃分進入獨立運行的程序片斷中,使整個程序能更迅速地響應用戶的請求。 最開始,線程只是用於分配單個處理器的處理時間的一種工具。但假如操作系統本身支持多個處理器,那麼每個線程都可分配給一個不同的處理器,真正進入「並行運算」狀態。從程序設計語言的角度看,多線程操作最有價值的特性之一就是程序員不必關心到底使用了多少個處理器。程序在邏輯意義上被分割為數個線程;假如機器本身安裝了多個處理器,那麼程序會運行得更快,毋需作出任何特殊的調校。根據前面的論述,大家可能感覺線程處理非常簡單。但必須注意一個問題:共享資源!如果有多個線程同時運行,而且它們試圖訪問相同的資源,就會遇到一個問題。舉個例子來說,兩個線程不能將信息同時發送給一台列印機。為解決這個問題,對那些可共享的資源來說(比如列印機),它們在使用期間必須進入鎖定狀態。所以一個線程可將資源鎖定,在完成了它的任務後,再解開(釋放)這個鎖,使其他線程可以接著使用同樣的資源。 多線程是為了同步完成多項任務,不是為了提高運行效率,而是為了提高資源使用效率來提高系統的效率。線程是在同一時間需要完成多項任務的時候實現的。 一個採用了多線程技術的應用程序可以更好地利用系統資源。其主要優勢在於充分利用了CPU的空閑時間片,可以用盡可能少的時間來對用戶的要求做出響應,使得進程的整體運行效率得到較大提高,同時增強了應用程序的靈活性。更為重要的是,由於同一進程的所有線程是共享同一內存,所以不需要特殊的數據傳送機制,不需要建立共享存儲區或共享文件,從而使得不同任務之間的協調操作與運行、數據的交互、資源的分配等問題更加易於解決。進程間通信(IPC,Inter-Process Communication),指至少兩個進程或線程間傳送數據或信號的一些技術或方法。進程是計算機系統分配資源的最小單位。每個進程都有自己的一部分獨立的系統資源,彼此是隔離的。為了能使不同的進程互相訪問資源並進行協調工作,才有了進程間通信。這些進程可以運行在同一計算機上或網路連接的不同計算機上。 進程間通信技術包括消息傳遞、同步、共享內存和遠程過程調用。
⑥ 訪問同一個web站點.如果只有你和我兩個人訪問.那麼這站點的伺服器會有幾個相關的
這和幾個用戶沒關系,和有幾個請求有點關系,具體看下面這篇文檔:
servlet多線程
Servlet體系結構是建立在Java多線程機制之上的,它的生命周期是由Web容器負責的。當客戶端第一次請求某個Servlet時,Servlet容器將會根據web.xml配置文件實例化這個Servlet類。當有新的客戶端請求該Servlet時,一般不會再實例化該Servlet類,也就是有多個線程在使用這個實例。 這樣,當兩個或多個線程同時訪問同一個Servlet時,可能會發生多個線程同時訪問同一資源的情況,數據可能會變得不一致。所以在用Servlet構建的Web應用時如果不注意線程安全的問題,會使所寫的Servlet程序有難以發現的錯誤。
實例變數不正確的使陵銀用是造成Servlet線程不安全的主要原因。下面針對該問題給出了三種解決方案並對方案的選取給出了一些參考性的建議。
1、實現 SingleThreadModel 介面
該介面指定了系統如何處理對同一個Servlet的調用。如果一個Servlet被這個介面指定,那麼在這個Servlet中的service方法將不會有兩個線程被同時執行,當然也就不存在線程安全的問題。這種方法只要將前面的Concurrent Test類的類頭定義更改為:
Public class Concurrent Test extends HttpServlet implements SingleThreadModel {
…………
}
2、同步對共享數據的操作
使用synchronized 關鍵字能保證一次只有一個線程可以訪問被保護的區段,在本論文中的Servlet可以通過同步塊操作來保證線程的安全。同步後的代碼如下:
…………
Public class Concurrent Test extends HttpServlet { …………
Username = request.getParameter ("username");
Synchronized (this){
Output = response.getWriter ();
Try {
Thread. Sleep (5000);
} Catch (Interrupted Exception e){}
output.println("用戶名:"+Username+"
");
}
}
}
3、避免使用實例變數
本實例中的線程安全問題是由實例變數造薯廳成的,只要在Servlet裡面的任何方法裡面都不使用實例變數,那麼該Servlet就是線程安全的。
修正上面的Servlet代碼,將實例變數改為局部變數實現同樣的功能,代碼如下:
……
Public class Concurrent Test extends HttpServlet {public void service (HttpServletRequest request, HttpServletResponse
Response) throws ServletException, IOException {
Print Writer output;
String username;
Response.setContentType ("text/html; charset=gb2312");
……
}
}
對上面的三種方法進行測試,可以表明用它們都能設計出線程安全的Servlet程序。但是,如果一個Servlet實現了SingleThreadModel介面,Servlet引擎將為每個新的請求創建一個單獨的Servlet實例,這將引起大量的系統開銷。SingleThreadModel在Servlet2.4中已不再提倡使用;同樣如果在程序中使用同步來保護要使用的共享的數據,也會使系統的性能大大下降。這是因為被同步的代碼塊在同一時刻只能有一個線程執行它,使得其同時處理客戶請求的吞吐量降低,而且很多客戶處於阻塞狀態。另外為保證主存內容和線程的工作內存中的數據的一致性,要頻繁地刷新緩存,這也會大大地影響系統的性能。所以在實際的開發中也應避免或最小化 Servlet 中的同步代碼;在Serlet中避免使用實例變數是保證Servlet線程安全的最佳選擇。從Java 內存模型也可以知道,方尺手宴法中的臨時變數是在棧上分配空間,而且每個線程都有自己私有的棧空間,所以它們不會影響線程的安全。
補充:
servlet存在的多線程問題
實例變數: 實例變數是在堆中分配的,並被屬於該實例的所有線程共享,所以不是線程安全的.
JSP系統提供的8個類變數:
JSP中用到的OUT,REQUEST,RESPONSE,SESSION,CONFIG,PAGE,PAGECONXT是線程安全的,APPLICATION在整個系統內被使用,所以不是線程安全的.
局部變數: 局部變數在堆棧中分配,因為每個線程都有它自己的堆棧空間,所以是線程安全的.
靜態類: 靜態類不用被實例化,就可直接使用,也不是線程安全的.
外部資源: 在程序中可能會有多個線程或進程同時操作同一個資源(如:多個線程或進程同時對一個文件進行寫操作).
此時也要注意同步問題. 使它以單線程方式執行,這時,仍然只有一個實例,所有客戶端的請求以串列方式執行。這樣會降低系統的性能
對於存在線程不安全的類,如何避免出現線程安全問題:
1、採用synchronized同步。缺點就是存在堵塞問題。
2、使用ThreadLocal(實際上就是一個HashMap),這樣不同的線程維護自己的對象,線程之間相互不幹擾。
ThreadLocal的設計
首先看看ThreadLocal的介面:
Object get() ; // 返回當前線程的線程局部變數副本 protected Object
initialValue(); // 返回該線程局部變數的當前線程的初始值
void set(Object value); // 設置當前線程的線程局部變數副本的值
ThreadLocal有3個方法,其中值得注意的是initialValue(),該方法是一個protected
的方法,顯然是為了子類重寫而特意實現的。該方法返回當前線程在該線程局部變數的初始
值,這個方法是一個延遲調用方法,在一個線程第1次調用get()或者set(Object)時才執行
,並且僅執行1次。ThreadLocal中的確實實現直接返回一個null:
protected Object initialValue() { return null; }
ThreadLocal是如何做到為每一個線程維護變數的副本的呢?其實實現的思路很簡單,
在ThreadLocal類中有一個Map,用於存儲每一個線程的變數的副本。比如下面的示例實現:
public class ThreadLocal
{
private Map values = Collections.synchronizedMap(new HashMap());
public Object get()
{
Thread curThread = Thread.currentThread();
Object o = values.get(curThread);
if (o == null && !values.containsKey(curThread))
{
o = initialValue();
values.put(curThread, o);
}
return o;
}
public void set(Object newValue)
{
values.put(Thread.currentThread(), newValue);
}
public Object initialValue()
{
return null;
}
}
當然,這並不是一個工業強度的實現,但JDK中的ThreadLocal的實現總體思路也類似於此。
ThreadLocal的使用
如果希望線程局部變數初始化其它值,那麼需要自己實現ThreadLocal的子類並重寫該
方法,通常使用一個內部匿名類對ThreadLocal進行子類化,比如下面的例子,SerialNum類
為每一個類分配一個序號:
public class SerialNum
{
// The next serial number to be assigned
private static int nextSerialNum = 0;
private static ThreadLocal serialNum = new ThreadLocal()
{
protected synchronized Object initialValue()
{
return new Integer(nextSerialNum++);
}
};
public static int get()
{
return ((Integer) (serialNum.get())).intValue();
}
}
SerialNum類的使用將非常地簡單,因為get()方法是static的,所以在需要獲取當前線
程的序號時,簡單地調用:
int serial = SerialNum.get(); 即可。
在線程是活動的並且ThreadLocal對象是可訪問的時,該線程就持有一個到該線程局部
變數副本的隱含引用,當該線程運行結束後,該線程擁有的所以線程局部變數的副本都將失
效,並等待垃圾收集器收集。
ThreadLocal與其它同步機制的比較
ThreadLocal和其它同步機制相比有什麼優勢呢?ThreadLocal和其它所有的同步機制都
是為了解決多線程中的對同一變數的訪問沖突,在普通的同步機制中,是通過對象加鎖來實
現多個線程對同一變數的安全訪問的。這時該變數是多個線程共享的,使用這種同步機制需
要很細致地分析在什麼時候對變數進行讀寫,什麼時候需要鎖定某個對象,什麼時候釋放該
對象的鎖等等很多。所有這些都是因為多個線程共享了資源造成的。ThreadLocal就從另一
個角度來解決多線程的並發訪問,ThreadLocal會為每一個線程維護一個和該線程綁定的變
量的副本,從而隔離了多個線程的數據,每一個線程都擁有自己的變數副本,從而也就沒有
必要對該變數進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時
,可以把不安全的整個變數封裝進ThreadLocal,或者把該對象的特定於線程的狀態封裝進
ThreadLocal。
由於ThreadLocal中可以持有任何類型的對象,所以使用ThreadLocal get當前線程的值
是需要進行強制類型轉換。但隨著新的Java版本(1.5)將模版的引入,新的支持模版參數
的ThreadLocal<T>類將從中受益。也可以減少強制類型轉換,並將一些錯誤檢查提前到了編
譯期,將一定程度地簡化ThreadLocal的使用。
總結
當然ThreadLocal並不能替代同步機制,兩者面向的問題領域不同。同步機制是為了同
步多個線程對相同資源的並發訪問,是為了多個線程之間進行通信的有效方式;而
ThreadLocal是隔離多個線程的數據共享,從根本上就不在多個線程之間共享資源(變數)
,這樣當然不需要對多個線程進行同步了。所以,如果你需要進行多個線程之間進行通信,
則使用同步機制;如果需要隔離多個線程之間的共享沖突,可以使用ThreadLocal,這將極
大地簡化你的程序,使程序更加易讀、簡潔。
ThreadLocal常見用途:
存放當前session用戶
存放一些context變數,比如webwork的ActionContext
存放session,比如Spring hibernate orm的session
例子:用 ThreadLocal 實現每線程 Singleton
線程局部變數常被用來描繪有狀態「單子」(Singleton) 或線程安全的共享對象,或者是通過把不安全的整個變數封裝進 ThreadLocal,或者是通過把對象的特定於線程的狀態封裝進 ThreadLocal。例如,在與資料庫有緊密聯系的應用程序中,程序的很多方法可能都需要訪問資料庫。在系統的每個方法中都包含一個 Connection 作為參數是不方便的 — 用「單子」來訪問連接可能是一個雖然更粗糙,但卻方便得多的技術。然而,多個線程不能安全地共享一個 JDBC Connection。如清單 3 所示,通過使用「單子」中的 ThreadLocal,我們就能讓我們的程序中的任何類容易地獲取每線程 Connection 的一個引用。這樣,我們可以認為 ThreadLocal 允許我們創建每線程單子。
例:把一個 JDBC 連接存儲到一個每線程 Singleton 中
public class ConnectionDispenser {
private static class ThreadLocalConnection extends ThreadLocal {
public Object initialValue() {
return DriverManager.getConnection(ConfigurationSingleton.getDbUrl());
}
}
private ThreadLocalConnection conn = new ThreadLocalConnection();
public static Connection getConnection() {
return (Connection) conn.get();
}
}
注意:
理論上來說,ThreadLocal是的確是相對於每個線程,每個線程會有自己的ThreadLocal。但是上面已經講到,一般的應用伺服器都會維護一套線程池。因此,不同用戶訪問,可能會接受到同樣的線程。因此,在做基於TheadLocal時,需要謹慎,避免出現ThreadLocal變數的緩存,導致其他線程訪問到本線程變數。