多線程技術(線程的創建Thread和Runnble,死鎖,線程間通信,join,yield)

 

多線程技術          

1.多線程概述

(1)進程:正在執行中的程序,比如QQ,javac等

(2)線程:進程中的一個獨立控制單元,線程控制着進程的執行。一個進程至少有一個線

(3)多線程的好處:可使程序產生同時運行的效果,多線程下載可提高效率。

2.多線程的兩種創建方式:

第一種方式:繼承Thread類

創建步驟:

(1)定義一個類繼承Thread(那麼此類也就變成了Thread類,擁有Start方法。

(2)複寫Thread類中的run方法(將需要使用多線程運行的代碼存在run方法,讓線程運行)

(3)調用線程的start方法.

注意:start():開啓一個新線程並運行run方法中的代碼,

而調用run方法只是對象調用方法,而不會創建新的線程。

 

第二種方式:實現Runnable接口。

創建步驟:

(1) 定義類實現Runnable接口

(2)覆蓋Runnable接口中的run方法。(還沒有擁有線程)

(3)通過Thread創建線程對象。

(4)將Runnable接口的子類對象作爲實際參數傳遞給Thread類的構造函數。

(5)調用Thread類的Start方法開啓線程,Runnable接口的run方法即可運行。

3.實現方式和繼承方式的區別

(1)繼承了一個類不能再繼承其他類,java只支持單繼承,這樣就會出現類繼承的侷限性。

(2)繼承Thread:線程代碼存放在Thread類的run方法中,直接就可以調用子類的Start方法即可開啓線程。

(3)實現Runnable:線程代碼存放在Runnable接口的子類的run方法中,開啓線程還需要new Thread();

(4)在定義線程時,建議使用實現方式。

4.線程的狀態和獲取線程對象以及名稱

線程的狀態: 1被創建——2運行——3阻塞(臨時狀態,具備執行資格但沒執行)——4凍結———5消亡。

獲取都有自己的名稱:Thread-編號從0開始

獲取對象方法:

static Thread currentThread()獲取當前線程對象。getName()獲取線程名稱。setName()設置線程名稱。

5.線程的安全解決

(1)產生安全問題的原因:當多個線程在操作同一個共享數據時,

一個線程還沒執行完,另一個線程參與進來,導致共享數據產生了錯誤。

(2)解決辦法:

同步代碼塊: synchronized(鎖對象){需要被同步的代碼數據;}

<1>對象如同鎖,持有鎖的線程纔可以在同步中執行。

<2>同步的前提:必須要有兩個或兩個以上的線程,必須是多個線程使用的同一個鎖對象。

同步函數:

非靜態同步函數的鎖:this

函數需要被對象調用,那麼函數都有一個所屬對象引用就是this,所以同步函數使用的鎖是this.

靜態同步函數的鎖:class對象

因爲靜態方法中不可以定義this,所以鎖不可能是this。靜態進內存時,內存中沒有本類對象,

但是一定有該類對應的字節碼文件對象,類名.class,該對象的類型是class.

6死鎖:同步中鉗套同步容易出現死鎖現象,應該避免這樣現象發生。

class Test implements Runnable
{
	private boolean flag;
	Test(boolean flag)
	{
		this.flag = flag;
	}

	public void run()
	{
		if(flag)
		{
			while(true)
			{
				synchronized(MyLock.locka)
				{
					System.out.println(Thread.currentThread().getName()+"...if locka ");
					synchronized(MyLock.lockb)
					{
						System.out.println(Thread.currentThread().getName()+"..if lockb");					
					}
				}
			}
		}
		else
		{
			while(true)
			{
				synchronized(MyLock.lockb)
				{
					System.out.println(Thread.currentThread().getName()+"..else lockb");
					synchronized(MyLock.locka)
					{
						System.out.println(Thread.currentThread().getName()+".....else locka");
					}
				}
			}
		}
	}
}


class MyLock
{
	static Object locka = new Object();
	static Object lockb = new Object();
}

class  DeadLockTest
{
	public static void main(String[] args) 
	{
		Thread t1 = new Thread(new Test(true));
		Thread t2 = new Thread(new Test(false));
		t1.start();
		t2.start();
	}
}

 

 

 

 

 

 

 

 

 

 

7.線程間通信

 

(1)線程間通信:

 

其實就是多個線程在操作同一個資源,但操作的動作不同。

 

(2)等待喚醒機制:

 

<1>wait(),notify(),notifyAll()都使用在同步中,因爲只有同步才具有鎖,所以要對持有鎖的線程操作。

 

<2>這些用來操作線程的方法爲什麼定義在Object類中?

 

a.這些方法存在於同步中。

 

b.使用這些方法時必須要標識所屬的同步的鎖。

 

c.等待和喚醒必須是同一個鎖。

 

d.鎖可以是任意對象,所以任意對象調用的方法一定定義在Object中。

 

(3)wait(),sleep()的區別:

 

wait():釋放資源,釋放鎖。

 

sleep():釋放資源,不釋放鎖。

 

(3)舉例:生產者與消費者

 

<1>對於多個生產者和消費者,爲讓被喚醒的線程再一次判斷標記,故要定義while判斷標記。

 

<2>爲什麼定義notifyAll?

 

因爲需要喚醒對方線程,只用notify容易出現只喚醒本方線程的情況,導致程序中的所有

 

線程都等待。

 

<3>JDK1.5提供的多線程升級解決方案。

 

將同步synchronized替換成現實Lock操作。將Object中的wait,notify,notifyAll替換成了

 

condition對象。該對象可以用Lock鎖進行獲取。

 

8.停止線程:

 

(1)stop方法已經過時。

 

(2)如何停止線程?

 

只有一種,就是讓run方法結束,開啓多線程運行,運行代碼通常是循環結構。只要控制住循環,

 

就可以讓run方法結束,也就是線程結束。

 

(3)特殊情況:

 

<1>當線程處於了凍結狀態,就不會讀到標記,那麼線程就不會結束。

 

<2>當沒有指定的方式讓凍結的線程恢復到運行狀態時,這時需要對凍結進行清除,強制讓線程恢復

 

到運行狀態中來,這樣就可以操作標記讓線程結束。

 

(4)Thread類提供該方法:interrupt()

 

9.守護線程:

 

setDaemon:

 

public final void setDaemon(boolean on)

 

(1)當正在運行的線程都是守護線程時,JVM退出。

 

(2)該方法必須在啓動線程前調用。

 

(3)主線程是前臺線程,前臺線程一結束,守護線程自動結束。

 

10.join方法:

 

join://搶奪CPU執行權

 

public final void join()

 

throws InterruptedException

 

等待該線程終止

 

(1)當A線程執行到了B線程的join()方法時,A就會等待,等B線程都執行完,A纔會執行。

 

(2)join可以用來臨時加入線程執行。

 

11.優先級&yield方法

 

setPriority(int newPriority)

 

更改線程的優先級(默認是5)

 

(1) MAX_PRIORITY-->10

 

NORM_PRIORITY--->5

 

MIN_PRIORITY--->1

 

(2)注:在任務管理器的進程中,也可進行優先級設置。

 

yield:臨時停止

 

public static void yield()

 

暫停當前正在執行的線程對象,並執行其他線程。yield可稍微減緩線程的運行,

 

使線程達到接近平均運行的效果。

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章