程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> java多線程具體總結

java多線程具體總結

編輯:關於JAVA

java多線程具體總結。本站提示廣大學習愛好者:(java多線程具體總結)文章只能為提供參考,不一定能成為您想要的結果。以下是java多線程具體總結正文


1、Thread.start()與Thread.run()的差別

經由過程挪用Thread類的start()辦法來啟動一個線程,這時候此線程是處於停當狀況,並沒有運轉。然後經由過程此Thread類挪用辦法run()來完成其運轉操作的,這裡辦法run()稱為線程體,它包括了要履行的這個線程的內容,Run辦法運轉停止,此線程終止,而CPU再運轉其它線程。

而假如直接用Run辦法,這只是挪用一個辦法罷了,法式中仍然只要“主線程”這一個線程,並沒有開拓新線程,其法式履行途徑照樣只要一條,如許就沒有到達寫線程的目標。

測試代碼以下

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

輸入成果為

>>以後過程為:main

>>以後過程為:main

改成用start辦法:

package thread;
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.start();
t2.start();
}
}

成果為:

>>以後過程為:Thread-1

>>以後過程為:Thread-2

2、ThreadLocal類詳解

ThreadLocal很輕易讓人望文生義,想固然地以為是一個“當地線程”。其實,ThreadLocal其實不是一個Thread,而是Thread的部分變量,或許把它定名為ThreadLocalVariable更輕易讓人懂得一些。當應用ThreadLocal保護變量時,ThreadLocal為每一個應用該變量的線程供給自力的變量正本,所以每個線程都可以自力地轉變本身的正本,而不會影響其它線程所對應的正本。

上面是線程部分變量(ThreadLocal variables)的症結點:

一個線程部分變量(ThreadLocal variables)為每一個線程便利地供給了一個零丁的變量。在多個線程操作該變量時刻可以或許互不影響,由於每一個線程操作的現實上是轉變量的正本。ThreadLocal實例平日作為靜態的公有的(private static)字段湧現在一個類中,這個類用來聯系關系線程。當多個線程拜訪ThreadLocal實例時,每一個線程保護ThreadLocal供給的自力的變量正本。

上面是測試代碼,用於測試:感化於一個對象下面的三個線程來操作統一個ThreadLoacl對象(integer 類型),看能否會湧現髒讀等景象:

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

運轉成果以下:

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

從下面可以看出,完整沒有湧現髒讀等的景象,是以ThreadLocal線程平安。

經常使用的應用:當DAO類作為一個單例類時,數據庫鏈接(connection)被每個線程自力的保護,互不影響。

可以用來掌握session的創立和應用,以下ThreadLocal<Session> session = new ThreadLocal<Session>();

ThreadLoacal與同步機制的比擬:

1、在同步機制中,經由過程對象的鎖機制包管統一時光只要一個線程拜訪變量。這時候該變量是多個線程同享的,應用同步機制請求法式慎密地剖析甚麼時刻對變量停止讀寫,甚麼時刻須要鎖定某個對象,甚麼時刻釋放對象鎖等復雜的成績,法式設計和編寫難度絕對較年夜。

2、而ThreadLocal則從另外一個角度來處理多線程的並發拜訪。ThreadLocal會為每個線程供給一個自力的變量正本,從而隔離了多個線程對數據的拜訪抵觸。由於每個線程都具有本身的變量正本,從而也就沒有需要對該變量停止同步了。ThreadLocal供給了線程平安的同享對象,在編寫多線程代碼時,可以把不平安的變量封裝進ThreadLocal。

3、歸納綜合起來講,關於多線程資本同享的成績,同步機制采取了“以時光換空間”的方法,而ThreadLocal采取了“以空間換時光”的方法。前者僅供給一份變量,讓分歧的線程列隊拜訪,爾後者為每個線程都供給了一份變量,是以可以同時拜訪而互不影響。

3、InvalidMonitorStateException異常

挪用wait()/notify()/notifyAll()中的任何一個辦法時,假如以後線程沒有取得該對象的鎖,那末就會拋出IllegalMonitorStateException的異常(也就是說法式在沒有履行對象的任何同步塊或許同步辦法時,依然測驗考試挪用wait()/notify()/notifyAll()時)。因為該異常是RuntimeExcpetion的子類,所以該異常紛歧定要捕捉(雖然你可以捕捉只需你情願).作為RuntimeException,此類異常不會在wait(),notify(),notifyAll()的辦法簽名說起。

以下代碼,劃線的部門會產生該異常,由於沒有對該對象履行同步操作。

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

4、sleep()和wait()和suspend()的差別

差別一:

sleep是Thread類的辦法,是線程用來掌握本身流程的,好比有一個要報時的線程,每秒中打印出一個時光,那末我就須要在print辦法後面加上一個sleep讓本身每隔一秒履行一次。就像個鬧鐘一樣。 sleep() 指導以後線程暫停履行指准時間,把履行機遇讓給其他線程,然則監控狀況仍然堅持,到時後會主動恢復。挪用sleep不會釋放對象鎖。

wait是Object類的辦法,用來線程間的通訊,這個辦法會使以後具有該對象鎖的線程期待,直到其他線程挪用notify辦法時再醒來,不外你也能夠給它指定一個時光,主動醒來。這個辦法重要是用在分歧線程之間的調劑。對象挪用wait()辦法招致本線程廢棄對象鎖,進入期待此對象的期待鎖定池,只要針對此對象收回notify辦法(或notifyAll)後本線程才進入對象鎖定池預備取得對象鎖進入運轉狀況。

差別二 :
 
挪用wait辦法會釋放以後線程的鎖,其實線程間的通訊是靠對象來治理的,一切操作一個對象的線程是這個對象經由過程本身的wait辦法來治理的。就似乎這個對象是電視機,三小我是三個線程,那末電視機的遙控器就是這個鎖,假設如今A拿著遙控器,電視機挪用wait辦法,那末A就交出本身的遙控器,由jVM虛擬機調劑,遙控器該交給誰。

挪用sleep辦法不會釋放鎖,由於sleep()是一個線程用於治理本身的辦法,不觸及線程通訊。照樣下面的例子,假如A拿遙控器的時代,他可以用本身的sleep每隔非常鐘調一次台,而在他調台歇息的非常鐘時代,遙控器還在他的手上,其別人沒法取得遙控器。

suspend() 辦法輕易產生逝世鎖。挪用suspend()的時刻,目的線程會停上去,但卻依然持有在這之前取得的鎖。此時,其他任何線程都不克不及拜訪鎖定的資本,除非被"掛起"的線程恢復運轉。對任何線程來講,假如它們想恢復目的線程,同時又試圖應用任何一個鎖定的資本,就會形成逝世鎖

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

1. 履行完同步代碼塊。

2. 在履行同步代碼塊的進程中,碰到異常而招致線程終止。

3. 在履行同步代碼塊的進程中,履行了鎖所屬對象的wait()辦法,這個線程會釋放鎖,停止對象的期待池。

在以下情形下,線程固然停滯履行,然則線程不會釋放鎖:

1. 在履行同步代碼塊的進程中,履行了Thread.sleep()辦法,以後線程廢棄CPU,開端睡眠,在睡眠中不會釋放鎖。

2. 在履行同步代碼塊的進程中,履行了Thread.yield()辦法,以後線程廢棄CPU,但不會釋放鎖。

3. 在履行同步代碼塊的進程中,其他線程履行了以後對象的suspend()辦法,以後線程被暫停,但不會釋放鎖。

5、在靜態辦法上應用同步

JAVA只辨認兩品種型的鎖:對象鎖和類鎖。

同步靜態辦法時會獲得該類的"Class”對象,所以當一個線程進入同步的靜態辦法中時,線程監督器獲得類自己的鎖,對全部類加鎖,其它線程不克不及進入這個類的任何靜態同步辦法。它不像實例辦法,由於多個線程可以同時拜訪分歧實例同步實例辦法。測試代碼以下:

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 {
//以下代碼創立了分歧的對象上的分歧線程,用來測試關於統一個類,會不會有鎖
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();
}
}

履行成果以下:
Running Thread-2
Running Thread-1
Method 2 called
Method 2 done
Method 1 called
Method 1 done

6、在一個對象上兩個線程可以在統一時光分離挪用兩個分歧的同步實例辦法嗎?

不克不及,由於一個對象曾經同步了實例辦法,線程獲得了對象的對象鎖。所以只要履行完該辦法釋放對象鎖後能力履行其它同步辦法。測試代碼以下:

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();
//以下代碼作為比較,創立分歧的對象,則就不會受對象鎖的攪擾了
//Common c1 = new Common();
//Common c2 = new Common();
//c1.start();
//c2.start();
}
}

履行成果以下:
Running Thread-1
Running Thread-2
Method 1 called
Method 1 done
Method 2 called
Method 2 done

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved