重慶分公司,新征程啟航
為企業提供網站建設、域名注冊、服務器等服務
為企業提供網站建設、域名注冊、服務器等服務
死鎖
創新互聯公司從2013年成立,先為寧蒗等服務建站,寧蒗等地企業,進行企業商務咨詢服務。為寧蒗企業網站制作PC+手機+微官網三網同步一站式服務解決您的所有建站問題。
死鎖是這樣一種情形:多個線程同時被阻塞,它們中的一個或者全部都在等待某個資源被釋放。由于線程被無限期地阻塞,因此程序不可能正常終止。
導致死鎖的根源在于不適當地運用“synchronized”關鍵詞來管理線程對特定對象的訪問。“synchronized”關鍵詞的作用是,確保在某個時刻只有一個線程被允許執行特定的代碼塊,因此,被允許執行的線程首先必須擁有對變量或對象的排他性的訪問權。當線程訪問對象時,線程會給對象加鎖,而這個鎖導致其它也想訪問同一對象的線程被阻塞,直至第一個線程釋放它加在對象上的鎖。
由于這個原因,在使用“synchronized”關鍵詞時,很容易出現兩個線程互相等待對方做出某個動作的情形。代碼一是一個導致死鎖的簡單例子。
//代碼一
class Deadlocker {
int field_1;
private Object lock_1 = new int[1];
int field_2;
private Object lock_2 = new int[1];
public void method1(int value) {
“synchronized” (lock_1) {
“synchronized” (lock_2) {
field_1 = 0; field_2 = 0;
}
}
}
public void method2(int value) {
“synchronized” (lock_2) {
“synchronized” (lock_1) {
field_1 = 0; field_2 = 0;
}
}
}
}
參考代碼一,考慮下面的過程:
◆ 一個線程(ThreadA)調用method1()。
◆ ThreadA在lock_1上同步,但允許被搶先執行。
◆ 另一個線程(ThreadB)開始執行。
◆ ThreadB調用method2()。
◆ ThreadB獲得lock_2,繼續執行,企圖獲得lock_1。但ThreadB不能獲得lock_1,因為ThreadA占有lock_1。
◆ 現在,ThreadB阻塞,因為它在等待ThreadA釋放lock_1。
◆ 現在輪到ThreadA繼續執行。ThreadA試圖獲得lock_2,但不能成功,因為lock_2已經被ThreadB占有了。
◆ ThreadA和ThreadB都被阻塞,程序死鎖。
當然,大多數的死鎖不會這么顯而易見,需要仔細分析代碼才能看出,對于規模較大的多線程程序來說尤其如此。好的線程分析工具,例如JProbe Threadalyzer能夠分析死鎖并指出產生問題的代碼位置。
隱性死鎖
隱性死鎖由于不規范的編程方式引起,但不一定每次測試運行時都會出現程序死鎖的情形。由于這個原因,一些隱性死鎖可能要到應用正式發布之后才會被發現,因此它的危害性比普通死鎖更大。下面介紹兩種導致隱性死鎖的情況:加鎖次序和占有并等待。
加鎖次序
當多個并發的線程分別試圖同時占有兩個鎖時,會出現加鎖次序沖突的情形。如果一個線程占有了另一個線程必需的鎖,就有可能出現死鎖。考慮下面的情形,ThreadA和ThreadB兩個線程分別需要同時擁有lock_1、lock_2兩個鎖,加鎖過程可能如下:
◆ ThreadA獲得lock_1;
◆ ThreadA被搶占,VM調度程序轉到ThreadB;
◆ ThreadB獲得lock_2;
◆ ThreadB被搶占,VM調度程序轉到ThreadA;
◆ ThreadA試圖獲得lock_2,但lock_2被ThreadB占有,所以ThreadA阻塞;
◆ 調度程序轉到ThreadB;
◆ ThreadB試圖獲得lock_1,但lock_1被ThreadA占有,所以ThreadB阻塞;
◆ ThreadA和ThreadB死鎖。
必須指出的是,在代碼絲毫不做變動的情況下,有些時候上述死鎖過程不會出現,VM調度程序可能讓其中一個線程同時獲得lock_1和lock_2兩個鎖,即線程獲取兩個鎖的過程沒有被中斷。在這種情形下,常規的死鎖檢測很難確定錯誤所在。
占有并等待
如果一個線程獲得了一個鎖之后還要等待來自另一個線程的通知,可能出現另一種隱性死鎖,考慮代碼二。
//代碼二
public class queue {
static java.lang.Object queueLock_;
Producer producer_;
Consumer consumer_;
public class Producer {
void produce() {
while (!done) {
“synchronized” (queueLock_) {
produceItemAndAddItToQueue();
“synchronized” (consumer_) {
consumer_.notify();
}
}
}
}
public class Consumer {
consume() {
while (!done) {
“synchronized” (queueLock_) {
“synchronized” (consumer_) {
consumer_.wait();
}
removeItemFromQueueAndProcessIt();
}
}
}
}
}
}
在代碼二中,Producer向隊列加入一項新的內容后通知Consumer,以便它處理新的內容。問題在于,Consumer可能保持加在隊列上的鎖,阻止Producer訪問隊列,甚至在Consumer等待Producer的通知時也會繼續保持鎖。這樣,由于Producer不能向隊列添加新的內容,而Consumer卻在等待Producer加入新內容的通知,結果就導致了死鎖。
在等待時占有的鎖是一種隱性的死鎖,這是因為事情可能按照比較理想的情況發展—Producer線程不需要被Consumer占據的鎖。盡管如此,除非有絕對可靠的理由肯定Producer線程永遠不需要該鎖,否則這種編程方式仍是不安全的。有時“占有并等待”還可能引發一連串的線程等待,例如,線程A占有線程B需要的鎖并等待,而線程B又占有線程C需要的鎖并等待等。
要改正代碼二的錯誤,只需修改Consumer類,把wait()移出“synchronized”()即可。
line = bufferedReader.readLine();//死鎖位置
會等待,所以會。
用另一個線程讀、主線程檢測是否命令終止了。
樓上的,如果是死循環,會一直輸出,不會停止,明顯是死鎖。
樓主:你這個是死鎖,主要就是出在循環的問題,你把super.notify();放在循環里就可以了。
一點一點講,A線程進入synchronized代碼塊中,首先喚醒一個正在等待的線程,當前肯定是沒有了,因為鎖的原因,然后A線程進入循環,輸出"線程A:10",進入等待。
此時執行的權限交給B線程,B線程進入synchronized代碼塊,執行super.notify();喚醒了A線程,但是由于同步機制,現在A處于就緒狀態,然后B線程進入循環,輸出“線程B:9”,進入等待,此前A線程已經喚醒了,執行權交給A線程,繼續執行,又循環一次,輸出“線程A:8”,然后進入等待,此時B現在也處于等待的狀態。然后就死鎖了。
樓主夠通俗不?
額,這么簡單,就直接定義一個類,該類隨便定義實例化個Object對象,然后在類中再定義2個內部線程類,線程一,對object使用synchronized,在synchronized塊中用個while(true)的死循環就好了,線程二,對object也是使用synchronized同步,至于synchronized塊中干啥,你自己看著辦,反正線程一死循環不會釋放object對象鎖,線程二是執行不到里面的代碼塊的
主線程保持著A對象的鎖意思就是主線程正在處理A對象,其他線程不能處理,要等待主線程結束之后其他線程才能處理A對象。
同理副線程正在處理B對象,A不能處理,所以主線程結束不了,一直在等待。
兩個線程都運行不下去了就叫做死鎖,程序崩潰。
加鎖的意思就是某線程正在處理某對象,其他線程不能處理。
手打不容易,明白不明白都給分吧- -、
1. 請把下面的java代碼用偽代碼寫出來
偽代碼(Pseudocode)是一種算法描述語言。
使用偽代碼的目的是為了使被描述的算法可以容易地以任何一種編程語言(Pascal,C,Java,etc)實現。因此,偽代碼必須結構清晰、代碼簡單、可讀性好,并且類似自然語言。
介于自然語言與編程語言之間。以編程語言的書寫形式指明算法職能。
使用偽代碼, 不用拘泥于具體實現。相比程序語言(例如Java, C++,C, Dephi 等等)它更類似自然語言。
它是半角式化、不標準的語言。可以將整個算法運行過程的結構用接近自然語言的形式(可以使用任何一種你熟悉的文字,關鍵是把程序的意思表達出來)描述出來。
String path = "***"File f = new File(path);public void test (F f)File []fs = f遍歷文件夾;for(。){ if(fs[i]是文件){ 輸入 }else{ 遞歸test(fs[i]); }}。
2. JAVA 偽代碼
提示輸入一個大于2且11的數字
輸入一整型數值給Vertices,
if(Vertices 3 || Vertices 11){
提示重新輸入且應輸入
退出程序
}else{
生成一個Vertices * Vertices 大小的數組Graph,
填充數組 :行號與列號相同填充0,其余填充10以內隨機數
交換元素:以[i][j]位置的數值與[j][i]位置的數值互換
最后打印數組各元素
}
3. 請把下列用java代碼 用偽代碼寫出來
偽代碼(Pseudocode)是一種算法描述語言。使用偽代碼的目的是為了使被描述的算法可以容易地以任何一種編程語言(Pascal,C,Java,etc)實現。因此,偽代碼必須結構清晰、代碼簡單、可讀性好,并且類似自然語言。 介于自然語言與編程語言之間。以編程語言的書寫形式指明算法職能。使用偽代碼, 不用拘泥于具體實現。相比程序語言(例如Java, C++,C, Dephi 等等)它更類似自然語言。它是半角式化、不標準的語言。可以將整個算法運行過程的結構用接近自然語言的形式(可以使用任何一種你熟悉的文字,關鍵是把程序的意思表達出來)描述出來。
String path = "***"
File f = new File(path);
public void test (F f)
File []fs = f遍歷文件夾;
for(。){
if(fs[i]是文件){
輸入
}else{
遞歸test(fs[i]);
}
}
4. 偽代碼怎么寫
偽代碼(Pseudocode)是一種算法描述語言。
使用偽代碼的目的是為了使被描述的算法可以容易地以任何一種編程語言(Pascal,C,Java,etc)實現。因此,偽代碼必須結構清晰、代碼簡單、可讀性好,并且類似自然語言。
介于自然語言與編程語言之間。 它以編程語言的書寫形式指明算法的職能。
相比于程序語言(例如Java, C++,C, Dephi 等等)它更類似自然語言。它是半角式化、不標準的語言。
我們可以將整個算法運行過程的結構用接近自然語言的形式(這里,你可以使用任何一種你熟悉的文字,中文,英文 等等,關鍵是你把你程序的意思表達出來)描述出來. 使用偽代碼, 可以幫助我們更好的表述算法, 不用拘泥于具體的實現. 人們在用不同的編程語言實現同一個算法時意識到,他們的實現(注意:這里是實現,不是功能)很不同。尤其是對于那些熟練于不同編程語言的程序員要理解一個(用其他編程語言編寫的程序的)功能時可能很難,因為程序語言的形式限制了程序員對程序關鍵部分的理解。
這樣偽代碼就應運而生了。 當考慮算法功能(而不是其語言實現)時,偽代碼常常得到應用。
計算機科學在教學中通常使用虛擬碼,以使得所有的程序員都能理解。 綜上,簡單的說,讓人便于理解的代碼。
不依賴于語言的,用來表示程序執行過程,而不一定能編譯運行的代碼。在數據結構講算法的時候用的很多。
5. 偽代碼的寫法
類Pascal語言的偽代碼的語法規則是: 在偽代碼中,每一條指令占一行(else if,例外)。指令后不跟任何符號(Pascal和C中語句要以分號結尾)。
偽代碼實例如下:
IF 九點以前 THEN
do 私人事務;
ELSE 9點到18點 THEN
工作;
ELSE
下班;
END IF
這樣不但可以達到文檔的效果,同時可以節約時間。更重要的是,使結構比較清晰,表達方式更加直觀。
偽代碼(Pseudocode)是一種算法描述語言。使用偽代碼的目的是為了使被描述的算法可以容易地以任何一種編程語言(Pascal,C,Java,etc)實現。因此,偽代碼必須結構清晰、代碼簡單、可讀性好,并且類似自然語言。 介于自然語言與編程語言之間。
它以編程語言的書寫形式指明算法的職能。相比于程序語言(例如Java, C++,C, Dephi 等等)它更類似自然語言。它是半角式化、不標準的語言。
我們可以將整個算法運行過程的結構用接近自然語言的形式(這里,你可以使用任何一種你熟悉的文字,中文,英文 等等,關鍵是你把你程序的意思表達出來)描述出來。使用偽代碼, 可以幫助我們更好的表述算法,不用拘泥于具體的實現。
6. 偽代碼的寫法
最低0.27元開通文庫會員,查看完整內容 原發布者:wangwenjxnu 偽代碼偽代碼是用介于自然語言和計算機語言之間的文字和符號來描述算法。
每一行(或幾行)表示一個基本操作。它不用圖形符號,因此書寫方便、格式緊湊,也比較好懂,便于向程序過渡。
偽代碼的7個主要部分:(1)算法名稱(2)指令序列(3)輸入/輸出(4)分支選擇(5)賦值(6)循環(7)算法結束1.算法名稱兩種表示算法的偽代碼:過程(Procedure)函數(Function)過程和函數的區別是:過程是執行一系列的操作,不需要返回操作的結果,無返回數據;函數是執行一系列的操作后,要將操作的結果返回,有返回數據。算法偽代碼的書寫規則:Procedure([])Function([])如:ProcedureHanoi_Tower()FunctionFac(x)表示名為Fac的一個函數。
FunctionProg(n)表示名為Prog的一個函數。2.指令序列指令序列是算法的主體。
指令序列的書寫規則:用Begin作為開始、用End作為結束;用“{”作為開始、用“/}”作為結束。例如:Begin指令序列;End或者:{指令序列;/}3.輸出/輸出輸入:Input輸出:Output或Return4.分支選擇兩種分支:IfThen{指令序列/}IfThen{。