国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

java多線程詳細(xì)總結(jié)

dance / 481人閱讀

摘要:當(dāng)多個(gè)線程訪問(wèn)實(shí)例時(shí),每個(gè)線程維護(hù)提供的獨(dú)立的變量副本。而則從另一個(gè)角度來(lái)解決多線程的并發(fā)訪問(wèn)。在執(zhí)行同步代碼塊的過(guò)程中,遇到異常而導(dǎo)致線程終止。在執(zhí)行同步代碼塊的過(guò)程中,其他線程執(zhí)行了當(dāng)前對(duì)象的方法,當(dāng)前線程被暫停,但不會(huì)釋放鎖。

一、Thread.start()與Thread.run()的區(qū)別
通過(guò)調(diào)用Thread類的start()方法來(lái)啟動(dòng)一個(gè)線程,這時(shí)此線程是處于就緒狀態(tài),并沒(méi)有運(yùn)行。然后通過(guò)此Thread類調(diào)用方法run()來(lái)完成其運(yùn)行操作的,這里方法run()稱為線程體,它包含了要執(zhí)行的這個(gè)線程的內(nèi)容,Run方法運(yùn)行結(jié)束,此線程終止,而CPU再運(yùn)行其它線程。

而如果直接用Run方法,這只是調(diào)用一個(gè)方法而已,程序中依然只有“主線程”這一個(gè)線程,并沒(méi)有開(kāi)辟新線程,其程序執(zhí)行路徑還是只有一條,這樣就沒(méi)有達(dá)到寫線程的目的。
測(cè)試代碼如下
代碼如下:

public class MyThread implements Runnable {
public void run() {
System.err.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread thread = new MyThread();
Thread t1 = new Thread(thread, "Thread-1");
Thread t2 = new Thread(thread, "Thread-2");
t1.run();
t2.run();
}
}

輸出結(jié)果為

當(dāng)前進(jìn)程為:main
當(dāng)前進(jìn)程為:main
改為用start方法:

代碼如下:

package thread;
public class MyThread implements Runnable {
public void run() {
System.err.println(">>當(dāng)前進(jìn)程為:"+Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread thread = new MyThread();
Thread t1 = new Thread(thread, "Thread-1");
Thread t2 = new Thread(thread, "Thread-2");
t1.start();
t2.start();
}
}

結(jié)果為:

當(dāng)前進(jìn)程為:Thread-1
當(dāng)前進(jìn)程為:Thread-2

二、ThreadLocal類詳解
ThreadLocal很容易讓人望文生義,想當(dāng)然地認(rèn)為是一個(gè)“本地線程”。其實(shí),ThreadLocal并不是一個(gè)Thread,而是Thread的局部變量,也許把它命名為ThreadLocalVariable更容易讓人理解一些。當(dāng)使用ThreadLocal維護(hù)變量時(shí),ThreadLocal為每個(gè)使用該變量的線程提供獨(dú)立的變量副本,所以每一個(gè)線程都可以獨(dú)立地改變自己的副本,而不會(huì)影響其它線程所對(duì)應(yīng)的副本。
下面是線程局部變量(ThreadLocal variables)的關(guān)鍵點(diǎn):
一個(gè)線程局部變量(ThreadLocal variables)為每個(gè)線程方便地提供了一個(gè)多帶帶的變量。在多個(gè)線程操作該變量時(shí)候能夠互不影響,因?yàn)槊總€(gè)線程操作的實(shí)際上是改變量的副本。ThreadLocal實(shí)例通常作為靜態(tài)的私有的(private static)字段出現(xiàn)在一個(gè)類中,這個(gè)類用來(lái)關(guān)聯(lián)線程。當(dāng)多個(gè)線程訪問(wèn)ThreadLocal實(shí)例時(shí),每個(gè)線程維護(hù)ThreadLocal提供的獨(dú)立的變量副本。
下面是測(cè)試代碼,用于測(cè)試:作用于一個(gè)對(duì)象上面的三個(gè)線程來(lái)操作同一個(gè)ThreadLoacl對(duì)象(integer 類型),看是否會(huì)出現(xiàn)臟讀等現(xiàn)象:
代碼如下:

public class Test implements Runnable {
private static ThreadLocal num = new ThreadLocal();
public void run() {
num.set(0);
for (int i = 0; i < 3; i++) {
num.set(num.get() + 1);
System.out.println(Thread.currentThread().getName() + ":num="

num.get());
}

}
public static void main(String[] args) {
Test test = new Test();
Thread t1 = new Thread(test, "Thread-1");
Thread t2 = new Thread(test, "Thread-2");
Thread t3 = new Thread(test, "Thread-3");
t1.start();
t2.start();
t3.start();
}
}

運(yùn)行結(jié)果如下:
Thread-3:num=1
Thread-2:num=1
Thread-1:num=1
Thread-2:num=2
Thread-3:num=2
Thread-2:num=3
Thread-1:num=2
Thread-1:num=3
Thread-3:num=3
從上面可以看出,完全沒(méi)有出現(xiàn)臟讀等的現(xiàn)象,因此ThreadLocal線程安全。
常用的使用:當(dāng)DAO類作為一個(gè)單例類時(shí),數(shù)據(jù)庫(kù)鏈接(connection)被每一個(gè)線程獨(dú)立的維護(hù),互不影響。
可以用來(lái)控制session的創(chuàng)建和使用,如下ThreadLocal session = new ThreadLocal();
ThreadLoacal與同步機(jī)制的比較:
1、在同步機(jī)制中,通過(guò)對(duì)象的鎖機(jī)制保證同一時(shí)間只有一個(gè)線程訪問(wèn)變量。這時(shí)該變量是多個(gè)線程共享的,使用同步機(jī)制要求程序慎密地分析什么時(shí)候?qū)ψ兞窟M(jìn)行讀寫,什么時(shí)候需要鎖定某個(gè)對(duì)象,什么時(shí)候釋放對(duì)象鎖等繁雜的問(wèn)題,程序設(shè)計(jì)和編寫難度相對(duì)較大。
2、而ThreadLocal則從另一個(gè)角度來(lái)解決多線程的并發(fā)訪問(wèn)。ThreadLocal會(huì)為每一個(gè)線程提供一個(gè)獨(dú)立的變量副本,從而隔離了多個(gè)線程對(duì)數(shù)據(jù)的訪問(wèn)沖突。因?yàn)槊恳粋€(gè)線程都擁有自己的變量副本,從而也就沒(méi)有必要對(duì)該變量進(jìn)行同步了。ThreadLocal提供了線程安全的共享對(duì)象,在編寫多線程代碼時(shí),可以把不安全的變量封裝進(jìn)ThreadLocal。
3、概括起來(lái)說(shuō),對(duì)于多線程資源共享的問(wèn)題,同步機(jī)制采用了“以時(shí)間換空間”的方式,而ThreadLocal采用了“以空間換時(shí)間”的方式。前者僅提供一份變量,讓不同的線程排隊(duì)訪問(wèn),而后者為每一個(gè)線程都提供了一份變量,因此可以同時(shí)訪問(wèn)而互不影響。

三、InvalidMonitorStateException異常
調(diào)用wait()/notify()/notifyAll()中的任何一個(gè)方法時(shí),如果當(dāng)前線程沒(méi)有獲得該對(duì)象的鎖,那么就會(huì)拋出IllegalMonitorStateException的異常(也就是說(shuō)程序在沒(méi)有執(zhí)行對(duì)象的任何同步塊或者同步方法時(shí),仍然嘗試調(diào)用wait()/notify()/notifyAll()時(shí))。由于該異常是RuntimeExcpetion的子類,所以該異常不一定要捕獲(盡管你可以捕獲只要你愿意).作為RuntimeException,此類異常不會(huì)在wait(),notify(),notifyAll()的方法簽名提及。
如下代碼,劃線的部分會(huì)發(fā)生該異常,因?yàn)闆](méi)有對(duì)該對(duì)象執(zhí)行同步操作。
代碼如下:

public class Common implements Runnable {
public synchronized void method1() throws InterruptedException {
Thread.sleep(1000);
System.out.println("Method 1 called");
Thread.sleep(1000);
System.out.println("Method 1 done");
}
public synchronized void method2() throws InterruptedException {
Thread.sleep(1000);
System.err.println("Method 2 called");
Thread.sleep(1000);
System.err.println("Method 2 done");
}
public void run() {
System.out.println("Running " + Thread.currentThread().getName());
try {
if (Thread.currentThread().getName().equals("Thread-1")) {
this.wait(1000);
method1();
} else {
method2();
notifyAll();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Common c = new Common();
Thread t1 = new Thread(c, "Thread-1");
Thread t2 = new Thread(c, "Thread-2");
t1.start();
t2.start();
}
}

改為一下代碼,劃線部分:
代碼如下:

public class Common implements Runnable {
public synchronized void method1() throws InterruptedException {
Thread.sleep(1000);
System.out.println("Method 1 called");
Thread.sleep(1000);
System.out.println("Method 1 done");
}
public synchronized void method2() throws InterruptedException {
Thread.sleep(1000);
System.err.println("Method 2 called");
Thread.sleep(1000);
System.err.println("Method 2 done");
}
public void run() {
System.out.println("Running " + Thread.currentThread().getName());
try {
if (Thread.currentThread().getName().equals("Thread-1")) {
synchronized(this){
this.wait(1000);
}
method1();
} else {
method2();
synchronized (this) {
notifyAll();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Common c = new Common();
Thread t1 = new Thread(c, "Thread-1");
Thread t2 = new Thread(c, "Thread-2");
t1.start();
t2.start();
}
}

四、sleep()和wait()和suspend()的區(qū)別
區(qū)別一:
sleep是Thread類的方法,是線程用來(lái)控制自身流程的,比如有一個(gè)要報(bào)時(shí)的線程,每一秒中打印出一個(gè)時(shí)間,那么我就需要在print方法前面加上一個(gè)sleep讓自己每隔一秒執(zhí)行一次。就像個(gè)鬧鐘一樣。 sleep() 指示當(dāng)前線程暫停執(zhí)行指定時(shí)間,把執(zhí)行機(jī)會(huì)讓給其他線程,但是監(jiān)控狀態(tài)依然保持,到時(shí)后會(huì)自動(dòng)恢復(fù)。調(diào)用sleep不會(huì)釋放對(duì)象鎖。
wait是Object類的方法,用來(lái)線程間的通信,這個(gè)方法會(huì)使當(dāng)前擁有該對(duì)象鎖的線程等待,直到其他線程調(diào)用notify方法時(shí)再醒來(lái),不過(guò)你也可以給它指定一個(gè)時(shí)間,自動(dòng)醒來(lái)。這個(gè)方法主要是用在不同線程之間的調(diào)度。對(duì)象調(diào)用wait()方法導(dǎo)致本線程放棄對(duì)象鎖,進(jìn)入等待此對(duì)象的等待鎖定池,只有針對(duì)此對(duì)象發(fā)出notify方法(或notifyAll)后本線程才進(jìn)入對(duì)象鎖定池準(zhǔn)備獲得對(duì)象鎖進(jìn)入運(yùn)行狀態(tài)。
區(qū)別二 :

調(diào)用wait方法會(huì)釋放當(dāng)前線程的鎖,其實(shí)線程間的通信是靠對(duì)象來(lái)管理的,所有操作一個(gè)對(duì)象的線程是這個(gè)對(duì)象通過(guò)自己的wait方法來(lái)管理的。就好像這個(gè)對(duì)象是電視機(jī),三個(gè)人是三個(gè)線程,那么電視機(jī)的遙控器就是這個(gè)鎖,假如現(xiàn)在A拿著遙控器,電視機(jī)調(diào)用wait方法,那么A就交出自己的遙控器,由jVM虛擬機(jī)調(diào)度,遙控器該交給誰(shuí)。
調(diào)用sleep方法不會(huì)釋放鎖,因?yàn)閟leep()是一個(gè)線程用于管理自己的方法,不涉及線程通信。還是上面的例子,如果A拿遙控器的期間,他可以用自己的sleep每隔十分鐘調(diào)一次臺(tái),而在他調(diào)臺(tái)休息的十分鐘期間,遙控器還在他的手上,其他人無(wú)法獲得遙控器。
suspend() 方法容易發(fā)生死鎖。調(diào)用suspend()的時(shí)候,目標(biāo)線程會(huì)停下來(lái),但卻仍然持有在這之前獲得的鎖。此時(shí),其他任何線程都不能訪問(wèn)鎖定的資源,除非被"掛起"的線程恢復(fù)運(yùn)行。對(duì)任何線程來(lái)說(shuō),如果它們想恢復(fù)目標(biāo)線程,同時(shí)又試圖使用任何一個(gè)鎖定的資源,就會(huì)造成死鎖
在以下情況下,持有鎖的線程會(huì)釋放鎖:

執(zhí)行完同步代碼塊。

在執(zhí)行同步代碼塊的過(guò)程中,遇到異常而導(dǎo)致線程終止。

在執(zhí)行同步代碼塊的過(guò)程中,執(zhí)行了鎖所屬對(duì)象的wait()方法,這個(gè)線程會(huì)釋放鎖,進(jìn)行對(duì)象的等待池。
在以下情況下,線程雖然停止執(zhí)行,但是線程不會(huì)釋放鎖:

在執(zhí)行同步代碼塊的過(guò)程中,執(zhí)行了Thread.sleep()方法,當(dāng)前線程放棄CPU,開(kāi)始睡眠,在睡眠中不會(huì)釋放鎖。

在執(zhí)行同步代碼塊的過(guò)程中,執(zhí)行了Thread.yield()方法,當(dāng)前線程放棄CPU,但不會(huì)釋放鎖。

在執(zhí)行同步代碼塊的過(guò)程中,其他線程執(zhí)行了當(dāng)前對(duì)象的suspend()方法,當(dāng)前線程被暫停,但不會(huì)釋放鎖。
五、在靜態(tài)方法上使用同步

JAVA只識(shí)別兩種類型的鎖:對(duì)象鎖和類鎖。
同步靜態(tài)方法時(shí)會(huì)獲取該類的"Class”對(duì)象,所以當(dāng)一個(gè)線程進(jìn)入同步的靜態(tài)方法中時(shí),線程監(jiān)視器獲取類本身的鎖,對(duì)整個(gè)類加鎖,其它線程不能進(jìn)入這個(gè)類的任何靜態(tài)同步方法。它不像實(shí)例方法,因?yàn)槎鄠€(gè)線程可以同時(shí)訪問(wèn)不同實(shí)例同步實(shí)例方法。測(cè)試代碼如下:
代碼如下:

public class Common implements Runnable {
public synchronized static void method1() throws InterruptedException {
Thread.sleep(1000);
System.out.println("Method 1 called");
Thread.sleep(1000);
System.out.println("Method 1 done");
}
public synchronized static void method2() throws InterruptedException {
Thread.sleep(1000);
System.err.println("Method 2 called");
Thread.sleep(1000);
System.err.println("Method 2 done");
}
public void run() {
System.out.println("Running " + Thread.currentThread().getName());
try {
if (Thread.currentThread().getName().equals("Thread-1")) {
method1();
} else {
method2();
// Thread.currentThread().notify();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
//以下代碼創(chuàng)建了不同的對(duì)象上的不同線程,用來(lái)測(cè)試對(duì)于同一個(gè)類,會(huì)不會(huì)有鎖
Common c1 = new Common();
Common c2 = new Common();
Thread t1 = new Thread(c1, "Thread-1");
Thread t2 = new Thread(c2, "Thread-2");
t1.start();
t2.start();
}
}

執(zhí)行結(jié)果如下:
Running Thread-2
Running Thread-1
Method 2 called
Method 2 done
Method 1 called
Method 1 done
六、在一個(gè)對(duì)象上兩個(gè)線程可以在同一時(shí)間分別調(diào)用兩個(gè)不同的同步實(shí)例方法嗎?
不能,因?yàn)橐粋€(gè)對(duì)象已經(jīng)同步了實(shí)例方法,線程獲取了對(duì)象的對(duì)象鎖。所以只有執(zhí)行完該方法釋放對(duì)象鎖后才能執(zhí)行其它同步方法。測(cè)試代碼如下:
代碼如下:

public class Common implements Runnable {
public synchronized void method1() throws InterruptedException {
Thread.sleep(1000);
System.out.println("Method 1 called");
Thread.sleep(1000);
System.out.println("Method 1 done");
}
public synchronized void method2() throws InterruptedException {
Thread.sleep(1000);
System.err.println("Method 2 called");
Thread.sleep(1000);
System.err.println("Method 2 done");
}
public void run() {
System.out.println("Running " + Thread.currentThread().getName());
try {
if (Thread.currentThread().getName().equals("Thread-1")) {
method1();
} else {
method2();
// Thread.currentThread().notify();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Common c = new Common();
Thread t1 = new Thread(c, "Thread-1");
Thread t2 = new Thread(c, "Thread-2");
t1.start();
t2.start();
//以下代碼作為對(duì)比,創(chuàng)建不同的對(duì)象,則就不會(huì)受對(duì)象鎖的干擾了
//Common c1 = new Common();
//Common c2 = new Common();
//c1.start();
//c2.start();
}
}

執(zhí)行結(jié)果如下:
Running Thread-1
Running Thread-2
Method 1 called
Method 1 done
Method 2 called

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/65453.html

相關(guān)文章

  • 詳細(xì)Java面試題總結(jié)(二)之Java基礎(chǔ)知識(shí)篇

    摘要:超詳細(xì)的面試題總結(jié)一之基本知識(shí)多線程和虛擬機(jī)創(chuàng)建線程有幾種不同的方式你喜歡哪一種為什么繼承類實(shí)現(xiàn)接口應(yīng)用程序可以使用框架來(lái)創(chuàng)建線程池實(shí)現(xiàn)接口。死亡線程方法執(zhí)行結(jié)束,或者因異常退出了方法,則該線程結(jié)束生命周期。死亡的線程不可再次復(fù)生。 超詳細(xì)的Java面試題總結(jié)(一)之Java基本知識(shí) 多線程和Java虛擬機(jī) 創(chuàng)建線程有幾種不同的方式?你喜歡哪一種?為什么? 繼承Thread類 實(shí)現(xiàn)R...

    wangjuntytl 評(píng)論0 收藏0
  • Java開(kāi)發(fā)

    摘要:大多數(shù)待遇豐厚的開(kāi)發(fā)職位都要求開(kāi)發(fā)者精通多線程技術(shù)并且有豐富的程序開(kāi)發(fā)調(diào)試優(yōu)化經(jīng)驗(yàn),所以線程相關(guān)的問(wèn)題在面試中經(jīng)常會(huì)被提到。將對(duì)象編碼為字節(jié)流稱之為序列化,反之將字節(jié)流重建成對(duì)象稱之為反序列化。 JVM 內(nèi)存溢出實(shí)例 - 實(shí)戰(zhàn) JVM(二) 介紹 JVM 內(nèi)存溢出產(chǎn)生情況分析 Java - 注解詳解 詳細(xì)介紹 Java 注解的使用,有利于學(xué)習(xí)編譯時(shí)注解 Java 程序員快速上手 Kot...

    LuDongWei 評(píng)論0 收藏0
  • java

    摘要:多線程編程這篇文章分析了多線程的優(yōu)缺點(diǎn),如何創(chuàng)建多線程,分享了線程安全和線程通信線程池等等一些知識(shí)。 中間件技術(shù)入門教程 中間件技術(shù)入門教程,本博客介紹了 ESB、MQ、JMS 的一些知識(shí)... SpringBoot 多數(shù)據(jù)源 SpringBoot 使用主從數(shù)據(jù)源 簡(jiǎn)易的后臺(tái)管理權(quán)限設(shè)計(jì) 從零開(kāi)始搭建自己權(quán)限管理框架 Docker 多步構(gòu)建更小的 Java 鏡像 Docker Jav...

    honhon 評(píng)論0 收藏0
  • Java學(xué)習(xí)路線總結(jié),搬磚工逆襲Java架構(gòu)師(全網(wǎng)最強(qiáng))

    摘要:哪吒社區(qū)技能樹(shù)打卡打卡貼函數(shù)式接口簡(jiǎn)介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號(hào)作者架構(gòu)師奮斗者掃描主頁(yè)左側(cè)二維碼,加入群聊,一起學(xué)習(xí)一起進(jìn)步歡迎點(diǎn)贊收藏留言前情提要無(wú)意間聽(tīng)到領(lǐng)導(dǎo)們的談話,現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨(dú)立帶隊(duì)的人太少,簡(jiǎn)而言之,不缺干 ? 哪吒社區(qū)Java技能樹(shù)打卡?【打卡貼 day2...

    Scorpion 評(píng)論0 收藏0
  • 詳細(xì)Java面試題總結(jié)(一)之Java基礎(chǔ)知識(shí)篇

    摘要:最近在備戰(zhàn)面試的過(guò)程中,整理一下面試題。成員變量如果沒(méi)有被賦初值,則會(huì)自動(dòng)以類型的默認(rèn)值而賦值一種情況例外被修飾但沒(méi)有被修飾的成員變量必須顯示地賦值而局部變量則不會(huì)自動(dòng)賦值。   最近在備戰(zhàn)面試的過(guò)程中,整理一下面試題。大多數(shù)題目都是自己手敲的,網(wǎng)上也有很多這樣的總結(jié)。自己感覺(jué)總是很亂,所以花了很久把自己覺(jué)得重要的東西總結(jié)了一下。 面向?qū)ο蠛兔嫦蜻^(guò)程的區(qū)別 面向過(guò)程:  優(yōu)點(diǎn):性能比面...

    vpants 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<