最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2013年10月12日 09:19:25   作者:  
以下小編就對java中的多線程進(jìn)行了詳細(xì)的總結(jié)分析,需要的朋友可以過來參考下,希望對大家有所幫助

一、Thread.start()與Thread.run()的區(qū)別

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

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

測試代碼如下

復(fù)制代碼 代碼如下:

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方法:

復(fù)制代碼 代碼如下:

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)為是一個“本地線程”。其實,ThreadLocal并不是一個Thread,而是Thread的局部變量,也許把它命名為ThreadLocalVariable更容易讓人理解一些。當(dāng)使用ThreadLocal維護(hù)變量時,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應(yīng)的副本。

下面是線程局部變量(ThreadLocal variables)的關(guān)鍵點:

一個線程局部變量(ThreadLocal variables)為每個線程方便地提供了一個單獨的變量。在多個線程操作該變量時候能夠互不影響,因為每個線程操作的實際上是改變量的副本。ThreadLocal實例通常作為靜態(tài)的私有的(private static)字段出現(xiàn)在一個類中,這個類用來關(guān)聯(lián)線程。當(dāng)多個線程訪問ThreadLocal實例時,每個線程維護(hù)ThreadLocal提供的獨立的變量副本。

下面是測試代碼,用于測試:作用于一個對象上面的三個線程來操作同一個ThreadLoacl對象(integer 類型),看是否會出現(xiàn)臟讀等現(xiàn)象:

復(fù)制代碼 代碼如下:

public class Test implements Runnable {
private static ThreadLocal<Integer> num = new ThreadLocal<Integer>();
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();
}
}

運行結(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

從上面可以看出,完全沒有出現(xiàn)臟讀等的現(xiàn)象,因此ThreadLocal線程安全。

常用的使用:當(dāng)DAO類作為一個單例類時,數(shù)據(jù)庫鏈接(connection)被每一個線程獨立的維護(hù),互不影響。

可以用來控制session的創(chuàng)建和使用,如下ThreadLocal<Session> session = new ThreadLocal<Session>();

ThreadLoacal與同步機制的比較:

1、在同步機制中,通過對象的鎖機制保證同一時間只有一個線程訪問變量。這時該變量是多個線程共享的,使用同步機制要求程序慎密地分析什么時候?qū)ψ兞窟M(jìn)行讀寫,什么時候需要鎖定某個對象,什么時候釋放對象鎖等繁雜的問題,程序設(shè)計和編寫難度相對較大。

2、而ThreadLocal則從另一個角度來解決多線程的并發(fā)訪問。ThreadLocal會為每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數(shù)據(jù)的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進(jìn)行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進(jìn)ThreadLocal。

3、概括起來說,對于多線程資源共享的問題,同步機制采用了“以時間換空間”的方式,而ThreadLocal采用了“以空間換時間”的方式。前者僅提供一份變量,讓不同的線程排隊訪問,而后者為每一個線程都提供了一份變量,因此可以同時訪問而互不影響。

三、InvalidMonitorStateException異常

調(diào)用wait()/notify()/notifyAll()中的任何一個方法時,如果當(dāng)前線程沒有獲得該對象的鎖,那么就會拋出IllegalMonitorStateException的異常(也就是說程序在沒有執(zhí)行對象的任何同步塊或者同步方法時,仍然嘗試調(diào)用wait()/notify()/notifyAll()時)。由于該異常是RuntimeExcpetion的子類,所以該異常不一定要捕獲(盡管你可以捕獲只要你愿意).作為RuntimeException,此類異常不會在wait(),notify(),notifyAll()的方法簽名提及。

如下代碼,劃線的部分會發(fā)生該異常,因為沒有對該對象執(zhí)行同步操作。

復(fù)制代碼 代碼如下:

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();
}
}

改為一下代碼,劃線部分:
復(fù)制代碼 代碼如下:

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類的方法,是線程用來控制自身流程的,比如有一個要報時的線程,每一秒中打印出一個時間,那么我就需要在print方法前面加上一個sleep讓自己每隔一秒執(zhí)行一次。就像個鬧鐘一樣。 sleep() 指示當(dāng)前線程暫停執(zhí)行指定時間,把執(zhí)行機會讓給其他線程,但是監(jiān)控狀態(tài)依然保持,到時后會自動恢復(fù)。調(diào)用sleep不會釋放對象鎖。

wait是Object類的方法,用來線程間的通信,這個方法會使當(dāng)前擁有該對象鎖的線程等待,直到其他線程調(diào)用notify方法時再醒來,不過你也可以給它指定一個時間,自動醒來。這個方法主要是用在不同線程之間的調(diào)度。對象調(diào)用wait()方法導(dǎo)致本線程放棄對象鎖,進(jìn)入等待此對象的等待鎖定池,只有針對此對象發(fā)出notify方法(或notifyAll)后本線程才進(jìn)入對象鎖定池準(zhǔn)備獲得對象鎖進(jìn)入運行狀態(tài)。

區(qū)別二 :
 
調(diào)用wait方法會釋放當(dāng)前線程的鎖,其實線程間的通信是靠對象來管理的,所有操作一個對象的線程是這個對象通過自己的wait方法來管理的。就好像這個對象是電視機,三個人是三個線程,那么電視機的遙控器就是這個鎖,假如現(xiàn)在A拿著遙控器,電視機調(diào)用wait方法,那么A就交出自己的遙控器,由jVM虛擬機調(diào)度,遙控器該交給誰。

調(diào)用sleep方法不會釋放鎖,因為sleep()是一個線程用于管理自己的方法,不涉及線程通信。還是上面的例子,如果A拿遙控器的期間,他可以用自己的sleep每隔十分鐘調(diào)一次臺,而在他調(diào)臺休息的十分鐘期間,遙控器還在他的手上,其他人無法獲得遙控器。

suspend() 方法容易發(fā)生死鎖。調(diào)用suspend()的時候,目標(biāo)線程會停下來,但卻仍然持有在這之前獲得的鎖。此時,其他任何線程都不能訪問鎖定的資源,除非被"掛起"的線程恢復(fù)運行。對任何線程來說,如果它們想恢復(fù)目標(biāo)線程,同時又試圖使用任何一個鎖定的資源,就會造成死鎖

在以下情況下,持有鎖的線程會釋放鎖:

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

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

3. 在執(zhí)行同步代碼塊的過程中,執(zhí)行了鎖所屬對象的wait()方法,這個線程會釋放鎖,進(jìn)行對象的等待池。

在以下情況下,線程雖然停止執(zhí)行,但是線程不會釋放鎖:

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

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

3. 在執(zhí)行同步代碼塊的過程中,其他線程執(zhí)行了當(dāng)前對象的suspend()方法,當(dāng)前線程被暫停,但不會釋放鎖。

五、在靜態(tài)方法上使用同步

JAVA只識別兩種類型的鎖:對象鎖和類鎖。

同步靜態(tài)方法時會獲取該類的"Class”對象,所以當(dāng)一個線程進(jìn)入同步的靜態(tài)方法中時,線程監(jiān)視器獲取類本身的鎖,對整個類加鎖,其它線程不能進(jìn)入這個類的任何靜態(tài)同步方法。它不像實例方法,因為多個線程可以同時訪問不同實例同步實例方法。測試代碼如下:

復(fù)制代碼 代碼如下:

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)建了不同的對象上的不同線程,用來測試對于同一個類,會不會有鎖
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

六、在一個對象上兩個線程可以在同一時間分別調(diào)用兩個不同的同步實例方法嗎?

不能,因為一個對象已經(jīng)同步了實例方法,線程獲取了對象的對象鎖。所以只有執(zhí)行完該方法釋放對象鎖后才能執(zhí)行其它同步方法。測試代碼如下:

復(fù)制代碼 代碼如下:

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();
//以下代碼作為對比,創(chuàng)建不同的對象,則就不會受對象鎖的干擾了
//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
Method 2 done

相關(guān)文章

  • 利用Java讀取Word表格中文本和圖片的方法實例

    利用Java讀取Word表格中文本和圖片的方法實例

    這篇文章主要給大家介紹了關(guān)于如何利用Java讀取Word表格中文本和圖片的相關(guān)資料,主要利用的是free spire.doc.jar 包,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2021-07-07
  • springmvc前臺向后臺傳值幾種方式總結(jié)(從簡單到復(fù)雜)

    springmvc前臺向后臺傳值幾種方式總結(jié)(從簡單到復(fù)雜)

    今天小編就為大家分享一篇springmvc前臺向后臺傳值幾種方式總結(jié)(從簡單到復(fù)雜),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • 希爾排序的算法代碼

    希爾排序的算法代碼

    希爾排序也是一種插入排序方法,實際上是一種分組插入方法。
    2013-03-03
  • 淺談Java中ThreadLocal引發(fā)的內(nèi)存泄漏

    淺談Java中ThreadLocal引發(fā)的內(nèi)存泄漏

    本文主要介紹了淺談Java中ThreadLocal引發(fā)的內(nèi)存泄漏,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • java中Unsafe的使用講解

    java中Unsafe的使用講解

    這篇文章主要介紹了java中Unsafe的使用講解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • JAVA?POI設(shè)置EXCEL單元格格式用法舉例

    JAVA?POI設(shè)置EXCEL單元格格式用法舉例

    這篇文章主要給大家介紹了關(guān)于JAVA?POI設(shè)置EXCEL單元格格式用法的相關(guān)資料,POI中可能會用到一些需要設(shè)置EXCEL單元格格式的操作,需要的朋友可以參考下
    2023-08-08
  • SpringBoot整合log4j日志與HashMap的底層原理解析

    SpringBoot整合log4j日志與HashMap的底層原理解析

    這篇文章主要介紹了SpringBoot整合log4j日志與HashMap的底層原理,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • SpringBoot+hutool實現(xiàn)圖片驗證碼

    SpringBoot+hutool實現(xiàn)圖片驗證碼

    本文主要介紹了SpringBoot+hutool實現(xiàn)圖片驗證碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • IDEA中安裝和使用Lombok插件的方法

    IDEA中安裝和使用Lombok插件的方法

    Lombok是一個可以通過簡單的注解形式來幫助我們簡化消除一些必須有但顯得很臃腫的Java代碼的工具,通過使用對應(yīng)的注解,可以在編譯源碼的時候生成對應(yīng)的方法,本文重點給大家介紹IDEA中安裝和使用Lombok插件的方法,感興趣的朋友一起看看吧
    2021-06-06
  • struts2實現(xiàn)文件下載功能

    struts2實現(xiàn)文件下載功能

    這篇文章主要為大家詳細(xì)介紹了struts2實現(xiàn)文件下載功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03

最新評論

沁源县| 红安县| 长寿区| 岢岚县| 新竹县| 耒阳市| 闽侯县| 乡城县| 彝良县| 罗源县| 东明县| 洪江市| 柳江县| 涞源县| 永年县| 色达县| 四川省| 榆中县| 乌兰浩特市| 罗田县| 安岳县| 黔江区| 汉寿县| 临江市| 固原市| 进贤县| 台前县| 西乌珠穆沁旗| 苍山县| 盐城市| 门头沟区| 大名县| 渝北区| 旬阳县| 宁津县| 图木舒克市| 太保市| 金乡县| 维西| 龙州县| 姜堰市|