Java基礎第十一天學習日記_線程、同步、死鎖

------- android培訓java培訓、期待與您交流! ----------

進程:是一個正在執行中的程序。

      每一個進程執行都有一個執行順序,該順序是一個執行路徑,或者叫一個控制單元。

線程:就是進程中的一個獨立的控制單元。線程在控制着進程的執行。

  一個進程中至少有一個線程。

  Java VM啓動的時候會有一個進程java.exe。該進程中至少一個線程負責java程序的執行。而且這個線程運行的代碼存在於main方法中。該線程稱爲主線程。其實更細節說明jvm,jvm啓動不止一個線程,還有負責垃圾回首機制的線程。

發現運行結果每一次都不同。因爲多個線程都獲取cpu的執行權。Cpu執行到誰,誰就運行。

除多核外,在某一個時刻,只能有一個程序在運行。Cpu在做着快速的切換,以達到看上去是同時運行的效果。我們可以形象把多線程的運行行爲在互相搶奪cpu的執行權。

這就是多線程的一個特性:隨機性。誰搶到誰執行,至於執行多長,cpu說的算。

線程有自己默認的名稱。Thread-編號,該編號從0開始。可以通過getName方法來獲取線程的名字。並且可以使用Thread的構造函數或者setName設置name參數:super(name);。static ThreadcurrentThread();獲取當前線程對象。

線程的五個狀態:

自定義線程:

通過對api的查找,java已經提供了對線程這類事物的描述。就是Thread類。

方法一創建線程:繼承Thread類。

1. 定義類繼承Thread。

2. 複寫Thread類中的run方法。(目的:將自定義代碼存儲在run方法。讓線程運行。也就是說run方法用於存儲線程要運行的代碼。)

3. 調用線程的start方法,該方法有兩個作用:啓動線程,調用run方法。(run方法和start方法的區別:start方法會開啓線程並執行該線程的run方法。Run方法僅僅是對象調用方法。而線程創建了,並沒有運行。)

public class ThreadDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Demo d1=new Demo(/*"one---"*/);
		Demo d2=new Demo(/*"two---"*/);
		d1.start();//開啓線程並執行該線程的run方法。
		d2.start();
		//d.run();僅僅是對象調用方法。而線程創建了,並沒有運行。
		for (int i = 0; i < 60; i++) {
			System.out.println("主線程"+i);
		}
	}

}
class Demo extends Thread
{
	/*Demo(String name)//通過構造函數傳入線程的名字。線程會有默認的名稱Thread-編號,編號從0開始。
	{
		super(name);
	}*/
	public void run()//其中的代碼是線程中要執行的代碼。
	{
		for (int i = 0; i < 60; i++) {
			System.out.println(this.getName()+i);//通過getName()方法獲得線程的名字。
		}
	}
}

方法二創建線程:實現Runable接口。步驟:

1. 定義類實現Runnable接口。

2. 覆蓋Runnable接口中的run方法。將線程要運行的代碼存放在該run方法中。

3. 通過Thread類建立線程對象。

4. 將Runnable接口的子類對戲那個作爲實際參數傳遞給Thread類的構造函數。因爲自定義的run方法所屬的對象是Runnable接口的子對象。所以要讓線程去指定指定對象的run方法。

5. 調用Thread類的start方法開啓線程並調用Runnable接口子類的run方法。

兩種方法有什麼區別呢?

繼承Thread:線程代碼存放在Thread子類run方法中。

實現Runnable:線程代碼存在接口的子類run方法中。避免了單繼承的侷限性。在定義線程時,建議使用實現方式。

public class Ticket {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TicketThread t=new TicketThread();//實現Runnable時的實現方法
		Thread t1=new Thread(t);//傳入的是一個實現了Runnable的對象。
		Thread t2=new Thread(t);
		Thread t3=new Thread(t);
		Thread t4=new Thread(t);
		/*TicketThread t1=new TicketThread();
		TicketThread t2=new TicketThread();
		TicketThread t3=new TicketThread();
		TicketThread t4=new TicketThread();//繼承Thread時的實現方法*/
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}
class TicketThread implements Runnable//extends Thread
{
	private static int num=100;
	public void run()
	{
		while (true)
		{
			if (num>=0) {
				System.out.println(Thread.currentThread().getName()+"賣出1張票,餘票爲:"+num--);
			}
		}
	}
}

多線程運行時會出現安全問題:

原因:當多條語句在操作同一個線程共享數據時,一個線程對多條語句只執行了一部分,還沒有執行完,另一個線程參與進來執行,導致共享數據的錯誤。

解決的思想:對多條操作共享數據的語句,只能讓一個線程都執行完,在執行過程中,其他線程不可以參與執行。

Java提供的解決方式:同步代碼塊。

好處:解決了多線程的安全問題。

弊端:多個線程需要判斷鎖,較爲消耗資源。

Synchronized(對象)

需要被同步的代碼

尋找需要加同步的代碼部分的方法:

1、明確那些代碼是多線程的運行代碼。

2、明確共享數據。

3、明確多線程代碼中那些語句是操作共享數據的。

這裏的對象參數如同鎖。持有鎖的現成可以在同步中執行。沒有持有鎖的線程即使獲取cpu的執行權,也進不去,因爲沒有獲取鎖。

同步的前提:

1. 必須要有兩個或者兩個以上的線程。

2. 必須是多個線程使用同一個鎖。

使用Synchronized修飾的函數爲同步函數。同步函數使用的鎖是this。如果同步函數

靜態修飾後,使用的鎖是該類對應的字節碼文件對象:類名.class。該對象的類型是class。

public class BankDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) 
	{
		Cus c=new Cus();
		Thread t1=new Thread(c);
		Thread t2=new Thread(c);
		t1.start();
		t2.start();
	}

}
class Bank
{
	private int sum;
	//Object obj=new Object();
	public synchronized void add(int n) 
	{
		//synchronized(obj)
		//{
			sum=sum+n;
			try{Thread.sleep(10);}catch(InterruptedException e){}
			System.out.println("sum="+sum);
		//}
	}
}
class Cus implements Runnable
{
	Bank b=new Bank();
	public void run()
	{
		for (int i = 0; i < 3; i++) 
		{
			b.add(100);
		}
	}
}

單例開發模式的懶漢式:

class  Single

{

private static Single s = null;

private Single(){}

public  static  Single  getInstance()

{

if(s==null)

{

synchronized(Single.class)

{

if(s==null)//先有一個A線程進來,判斷到此處,掛起。B線程進入,也判斷,也是空,掛起。A線程繼續,創建了一個對象,結束。B線程繼續,又創建了一個對象。單例設計模式。兩個對象。

s=new  Single();

}

}

return s;

}

}

懶漢式和餓漢式的區別在於延遲加載,懶漢式會出安全問題,通過同步解決,運行時程序會低效,通過雙重判斷解決。

死鎖:同步中嵌套同步會造成死鎖。

public class DeadThreadDemo {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread t1=new Thread(new Test(true));
		Thread t2=new Thread(new Test(false));
		t1.start();
		t2.start();
	}

}
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("if locka");
					synchronized(MyLock.lockb)
					{
						System.out.println("if lockb");
					}
				}
			}
		}
		else
		{
			while(true)
			{
				synchronized(MyLock.lockb)
				{
					System.out.println("else lockb");
					synchronized(MyLock.locka)
					{
						System.out.println("else locka");
					}
				}
			}
		}
	}
}
class MyLock
{
	static Object locka=new Object();
	static Object lockb=new Object();
}
------- android培訓java培訓、期待與您交流! ----------  詳細請查看:http://edu.csdn.net/heima/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章