多线程 调用 axis 报错_java笔记录(三、多线程)
1、進程和線程:
進程:正在進行的程序。每一個進程執行都有一個執行順序,該順序是一個執行路徑,或者叫一個控制單元。
線程:進程內部的一條執行路徑或者一個控制單元。
兩者的區別:
一個進程至少有一個線程
進程在執行過程中擁有獨立的內存單元,而多個線程共享內存;
2、jvm多線程的啟動是多線程嗎?
java的虛擬機jvm啟動的是單線程,就有發生內存泄露的可能,而我們使用java程序沒出現這樣的問題,
也就是jvm啟動至少有兩個線程,一個執行java程序,一個執行垃圾回收。所以是多線程。
2、多線程的優勢:
解決了多部分同時運行的問題,提高效率
3、線程的弊端:
線程太多會導致效率的降低,因為線程的執行依靠的是CPU的來回切換。
4、什么叫多線程:
一個進程中有多個線程,稱為多線程。
5、實現多線程的方法:
實現多線程可以通過繼承Thread類和實現Runnable接口。
(1)繼承Thread
定義一個類繼承Thread類
復寫Thread類中的public void run()方法,將線程的任務代碼封裝到run方法中
直接創建Thread的子類對象,創建線程
調用start()方法,開啟線程(調用線程的任務run方法)
//另外可以通過Thread的getName()獲取線程的名稱。
(2)實現Runnable接口;
定義一個類,實現Runnable接口;
覆蓋接口的public void run()的方法,將線程的任務代碼封裝到run方法中;
創建Runnable接口的子類對象
將Runnabl接口的子類對象作為參數傳遞給Thread類的構造函數,創建Thread類對象
(原因:線程的任務都封裝在Runnable接口子類對象的run方法中。
所以要在線程對象創建時就必須明確要運行的任務)。
調用start()方法,啟動線程。
兩種方法區別:
(1)實現Runnable接口避免了單繼承的局限性
(2)繼承Thread類線程代碼存放在Thread子類的run方法中
實現Runnable接口線程代碼存放在接口的子類的run方法中;
在定義線程時,建議使用實現Runnable接口,因為幾乎所有多線程都可以使用這種方式實現
6、創建線程是為什么要復寫run方法?
Thread類用于描述線程。Thread類定義了一個功能,用于存儲線程要運行的代碼,該存儲功能就是run方法。
7、start()和run方法有什么區別?
調用start方法方可啟動線程,而run方法只是thread的一個普通方法,調用run方法不能實現多線程;
Start()方法:
start方法用來啟動線程,實現了多線程運行,這時無需等待run方法體代碼執行完畢而直接繼續執行下面的
代碼。通過調用Thread類的start()方法來啟動一個線程,這時此線程處于就緒(可運行)狀態,并沒有運行,
一旦得到cpu時間片(執行權),就開始執行run()方法,這里方法run()稱為線程體,
它包含了要執行的這個線程的內容,Run方法運行結束,此線程隨即終止。
Run()方法:
run()方法只是Thread類的一個普通方法,如果直接調用Run方法,程序中依然只有主線程這一個線程,
其程序執行路徑還是只有一條,還是要等待run方法體執行完畢后才可繼續執行下面的代碼,
這樣就沒有達到多線程的目的。
8、線程的幾種狀態:
新建:new一個Thread對象或者其子類對象就是創建一個線程,當一個線程對象被創建,但是沒有開啟,這個時候,
只是對象線程對象開辟了內存空間和初始化數據。
就緒:新建的對象調用start方法,就開啟了線程,線程就到了就緒狀態。
在這個狀態的線程對象,具有執行資格,沒有執行權。
運行:當線程對象獲取到了CPU的資源。
在這個狀態的線程對象,既有執行資格,也有執行權。
凍結:運行過程中的線程由于某些原因(比如wait,sleep),釋放了執行資格和執行權。
當然,他們可以回到運行狀態。只不過,不是直接回到。
而是先回到就緒狀態。
死亡:當線程對象調用的run方法結束,或者直接調用stop方法,就讓線程對象死亡,在內存中變成了垃圾。
9、sleep()和wait()的區別:
(1)這兩個方法來自不同的類,sleep()來自Thread類,和wait()來自Object類。
(2)sleep是Thread的靜態類方法,誰調用的誰去睡覺,即使在a線程里調用了b的sleep方法,實際上還是a去睡覺,
要讓b線程睡覺要在b的代碼中調用sleep。而wait()是Object類的非靜態方法
(3)sleep()釋放資源不釋放鎖,而wait()釋放資源釋放鎖;
(4)使用范圍:wait,notify和notifyAll只能在同步控制方法或者同步控制塊里面使用,而sleep可以在任何地方使用
10、多線程安全問題:
(1)原因:當程序的多條語句在操作線程共享數據時(如買票例子中的票就是共享資源),由于線程的隨機性導致
一個線程對多條語句,執行了一部分還沒執行完,另一個線程搶奪到cpu執行權參與進來執行,
此時就導致共享數據發生錯誤。比如買票例子中打印重票和錯票的情況。
(2)解決方法:對多條操作共享數據的語句進行同步,一個線程在執行過程中其他線程不可以參與進來
11、Java中多線程同步是什么?
同步是用來解決多線程的安全問題的,在多線程中,同步能控制對共享數據的訪問。如果沒有同步,當一個線程在
修改一個共享數據時,而另外一個線程正在使用或者更新同一個共享數據,這樣容易導致程序出現錯誤的結果。
12、什么是鎖?鎖的作用是什么?
鎖就是對象
鎖的作用是保證線程同步,解決線程安全問題。
持有鎖的線程可以在同步中執行,沒有鎖的線程即使獲得cpu執行權,也進不去。
13、同步的前提:
(1)必須保證有兩個以上線程
(2)必須是多個線程使用同一個鎖,即多條語句在操作線程共享數據
(3)必須保證同步中只有一個線程在運行
14、同步的好處和弊端
好處:同步解決了多線程的安全問題
弊端:多線程都需要判斷鎖,比較消耗資源
15、同步的兩種表現形式:
(1)同步代碼塊:
可以指定需要獲取哪個對象的同步鎖,使用synchronized的代碼塊同樣需要鎖,但他的鎖可以是任意對象
考慮到安全問題,一般還是使用同一個對象,相對來說效率較高。
注意:
**雖然同步代碼快的鎖可以使任何對象,但是在進行多線程通信使用同步代碼快時,
必須保證同步代碼快的鎖的對象和,否則會報錯。
**同步函數的鎖是this,也要保證同步函數的鎖的對象和調用wait、notify和notifyAll的對象是
同一個對象,也就是都是this鎖代表的對象。
格式:
synchronized(對象)
{
需同步的代碼;
}
(2)同步函數
同步方法是指進入該方法時需要獲取this對象的同步鎖,在方法上使用synchronized關鍵字,
使用this對象作為鎖,也就是使用了當前對象,因為鎖住了方法,所以相對于代碼塊來說效率相對較低。
注:靜態同步函數的鎖是該方法所在的類的字節碼文件對象,即類名.class文件
格式:
修飾詞 synchronized 返回值類型 函數名(參數列表)
{
需同步的代碼;
}
在jdk1.5后,用lock鎖取代了synchronized,個人理解也就是對同步代碼塊做了修改,
并沒有提供對同步方法的修改,主要還是效率問題吧。
16、多線程的單例設計模式:保證某個類中內存中只有一個對象
(1)餓漢式:
class Single
{
private Single(){}//將構造函數私有化,不讓別的類建立該類對象
private static final Single s=new Single();//自己建立一個對象
public static Single getInstance()//提供一個公共訪問方式
{
return s;
}
}
(2)懶漢式:
class Single
{
private Single(){}
private static Single s;
public static Single getInstance()
{
if(s==null)
s=new Single();
return s;
}
}
餓漢式和懶漢式的區別:
**
餓漢式是類一加載進內存就創建好了對象;
懶漢式則是類加載進內存的時候,對象還沒有存在,只有調用了getInstance()方法時,對象才開始創建。
**
懶漢式是延遲加載,如果多個線程同時操作懶漢式時就有可能出現線程安全問題,解決線程安全問題
可以加同步來解決。但是加了同步之后,每一次都要比較鎖,效率就變慢了,
所以可以加雙重判斷來提高程序效率。
如將上述懶漢式的Instance函數改成同步:
public static Single getInstance()
{
if(s==null)
{
synchronized(Single.class)
{
if(s==null)
s=new Single();
}
}
return s;
}
17、死鎖
兩個線程對兩個同步對象具有循環依賴時,就會發生死鎖。即同步嵌套同步,而鎖卻不同。
18、wait()、sleep()、notify()、notifyAll()
wait():使一個線程處于等待狀態,并且釋放所持有的對象的lock。
sleep():使一個正在運行的線程處于睡眠狀態,是一個靜態方法,調用此方法要捕捉InterruptedException異常。
notify():喚醒一個處于等待狀態的線程,注意的是在調用此方法的時候,并不能確切的喚醒某一個等待狀態的線程,
而是由JVM確定喚醒哪個線程(一般是最先開始等待的線程),而且不是按優先級。
Allnotity():喚醒所有處入等待狀態的線程,注意并不是給所有喚醒線程一個對象的鎖,而是讓它們競爭。
18、為什么wait()、notify()、notifyAll()這些用來操作線程的方法定義在Object類中?
(1)這些方法只存在于同步中;
(2)使用這些方法時必須要指定所屬的鎖,即被哪個鎖調用這些方法;
(3)而鎖可以是任意對象,所以任意對象調用的方法就定義在Object中。
19、多線程間通訊:
多線程間通訊就是多個線程在操作同一資源,但是操作的動作不同.
(1)為什么要通信
多線程并發執行的時候, 如果需要指定線程等待或者喚醒指定線程, 那么就需要通信.比如生產者消費者的問題,
生產一個消費一個,生產的時候需要負責消費的進程等待,生產一個后完成后需要喚醒負責消費的線程,
同時讓自己處于等待,消費的時候負責消費的線程被喚醒,消費完生產的產品后又將等待的生產線程喚醒,
然后使自己線程處于等待。這樣來回通信,以達到生產一個消費一個的目的。
(2)怎么通信
在同步代碼塊中, 使用鎖對象的wait()方法可以讓當前線程等待, 直到有其他線程喚醒為止.
使用鎖對象的notify()方法可以喚醒一個等待的線程,或者notifyAll喚醒所有等待的線程.
多線程間通信用sleep很難實現,睡眠時間很難把握。
20、Lock和Condition
實現提供比synchronized方法和語句可獲得的更廣泛的鎖的操作,可支持多個相關的Condition對象
Lock是個接口
鎖是控制多個線程對共享數據進行訪問的工具。
JDK1.5中提供了多線程升級的解決方案:
將同步synchonized替換成了顯示的Lock操作,將Object中的wait、notify、notifyAll替換成了Condition對象。
該對象可以Lock鎖進行獲取
Lock的方法摘要:
void lock() 獲取鎖。
Condition newCondition() 返回綁定到此 Lock 實例的新 Condition 實例。
void unlock() 釋放鎖。
Condition方法摘要:
void await() 造成當前線程在接到信號或被中斷之前一直處于等待狀態。
void signal() 喚醒一個等待線程。
void signalAll() 喚醒所有等待線程。
21、停止線程:
stop方法已經過時,如何停止線程?
停止線程的方法只有一種,就是run方法結束。如何讓run方法結束呢?
開啟多線程運行,運行代碼通常是循環體,只要控制住循環,就可以讓run方法結束,也就是結束線程。
特殊情況:當線程屬于凍結狀態,就不會讀取循環控制標記,則線程就不會結束。
為解決該特殊情況,可引入Thread類中的Interrupt方法結束線程的凍結狀態;
當沒有指定的方式讓凍結線程恢復到運行狀態時,需要對凍結進行清除,強制讓線程恢復到運行狀態
22、interrupt:
void interrupt() 中斷線程:
中斷狀態將被清除,它還將收到一個 InterruptedException
22、守護線程(后臺線程)
setDaemon(boolean on):將該線程標記為守護線程或者用戶線程。
當主線程結束,守護線程自動結束,比如圣斗士星矢里面的守護雅典娜,
在多線程里面主線程就是雅典娜,守護線程就是圣斗士,主線程結束了,
守護線程則自動結束。
當正在運行的線程都是守護線程時,java虛擬機jvm退出;所以該方法必須在啟動線程前調用;
守護線程的特點:
守護線程開啟后和前臺線程共同搶奪cpu的執行權,開啟、運行兩者都沒區別,
但結束時有區別,當所有前臺線程都結束后,守護線程會自動結束。
23、多線程join方法:
void join() 等待該線程終止。
void join(long millis) 等待該線程終止的時間最長為 millis 毫秒。
throws InterruptedException
特點:當A線程執行到B線程的join方法時,A就會等待B線程都執行完,A才會執行
作用: join可以用來臨時加入線程執行;
24、多線程優先級:yield()方法
yield():暫停當前正在執行的線程對象,并執行其他線程
setPriority(int newPriority):更改線程優先級
int getPriority() 返回線程的優先級。
String toString() 返回該線程的字符串表示形式,包括線程名稱、優先級和線程組
(1)MAX_PRIORITY:最高優先級(10級)
(1)Min_PRIORITY:最低優先級(1級)
(1)Morm_PRIORITY:默認優先級(5級)
25、什么是ThreadLocal類,怎么使用它?
ThreadLocal類提供了線程局部 (thread-local) 變量。是一個線程級別的局部變量,并非“本地線程”。
ThreadLocal 為每個使用該變量的線程,提供了一個獨立的變量副本,每個線程修改副本時不影響其它線程對象的副本
下面是線程局部變量(ThreadLocal variables)的關鍵點:
一個線程局部變量(ThreadLocal variables)為每個線程方便地提供了一個單獨的變量。
ThreadLocal 實例通常作為靜態的私有的(private static)字段出現在一個類中,這個類用來關聯一個線程。
當多個線程訪問 ThreadLocal 實例時,每個線程維護 ThreadLocal 提供的獨立的變量副本。
常用的使用可在 DAO 模式中見到,當 DAO 類作為一個單例類時,
數據庫鏈接(connection)被每一個線程獨立的維護,互不影響。(基于線程的單例)
26、什么時候拋出InvalidMonitorStateException異常?為什么?
調用 wait ()/notify ()/notifyAll ()中的任何一個方法時,如果當前線程沒有獲得該對象的鎖,
那么就會拋出 IllegalMonitorStateException 的異常
也就是說程序在沒有執行對象的任何同步塊或者同步方法時,
仍然嘗試調用 wait ()/notify ()/notifyAll ()時。由于該異常是 RuntimeExcpetion 的子類,
所以該異常不一定要捕獲(盡管你可以捕獲只要你愿意
作為 RuntimeException,此類異常不會在 wait (),notify (),notifyAll ()的方法簽名提及。
27、在靜態方法上使用同步時會發生什么事?
同步靜態方法時會獲取該類的“Class”對象,所以當一個線程進入同步的靜態方法中時,
線程監視器獲取類本身的對象鎖,其它線程不能進入這個類的任何靜態同步方法。
它不像實例方法,因為多個線程可以同時訪問不同實例同步實例方法。
28、當一個同步方法已經執行,線程能夠調用對象上的非同步實例方法嗎?
可以,一個非同步方法總是可以被調用而不會有任何問題。
實際上,Java 沒有為非同步方法做任何檢查,鎖對象僅僅在同步方法或者同步代碼塊中檢查。
如果一個方法沒有聲明為同步,即使你在使用共享數據Java照樣會調用,而不會做檢查是否安全,
所以在這種情況下要特別小心。一個方法是否聲明為同步取決于臨界區訪問(critial section access),
如果方法不訪問臨界區(共享資源或者數據結構)就沒必要聲明為同步的。
29、在一個對象上兩個線程可以調用兩個不同的同步實例方法嗎?
不能,因為一個對象已經同步了實例方法,線程獲取了對象的對象鎖。
所以只有執行完該方法釋放對象鎖后才能執行其它同步方法。
30、什么是線程餓死,什么是活鎖?
線程餓死和活鎖雖然不像死鎖一樣是常見的問題,但是對于并發編程的設計者來說就像一次邂逅一樣。
當所有線程阻塞,或者由于需要的資源無效而不能處理,不存在非阻塞線程使資源可用。
JavaAPI 中線程活鎖可能發生在以下情形:
當所有線程在程序中執行 Object.wait (0),參數為 0 的 wait 方法。
程序將發生活鎖直到在相應的對象上有線程調用 Object.notify ()或者 Object.notifyAll ()。
當所有線程卡在無限循環中。
總結
以上是生活随笔為你收集整理的多线程 调用 axis 报错_java笔记录(三、多线程)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎样从frm ibd恢复mysql_怎样
- 下一篇: 人人商城生成app教程_人人商城APP打