1. 程式人生 > >java8-多執行緒

java8-多執行緒

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

程序:就是一個正在執行中的程式。每個程序都有一個執行順序,叫一個執行路徑,或一個控制單元。
執行緒:就是程序中的一個獨立的控制單元,執行緒在控制著程序的執行。一個程序中至少有一個執行緒。


Java VM 啟動時會有一個程序java.exe
程序中至少有一個執行緒在負責程式的執行,並且執行的程式碼存在於main方法中,稱之為主執行緒。
其實啟動時還有個垃圾回收機制的執行緒。
多執行緒的特性:隨機性,誰搶到執行權,誰執行。


Thread類中的run方法是用於儲存要執行的程式碼,要覆蓋。


使用方法:
一:繼承Thread類
1,定義類繼承Thread.
2,複寫Thread類中的run方法
目的為了把自定義的程式碼儲存到run方法中,並讓執行緒執行。
3,呼叫執行緒的start方法。作用(啟動執行緒,呼叫run方法)。


二:建立執行緒的第二種方式,實現Runnable介面。
步驟:
1,定義類實現Runnable介面
2,覆蓋Runnable介面中的run方法(將執行緒要執行的程式碼存放在該run方法中)
3,通過Thread類建立執行緒物件
4,將Runnable介面的子類物件作為實際引數傳遞給Thread類的建構函式(因為自定義的run方法所屬的物件是Runnable介面的子類物件,所以要讓執行緒去執行指定物件的run方法,必須要明確該run方法所屬的物件)
5,呼叫Thread類的start方法開啟執行緒並呼叫Runnable介面子類的run方法


繼承和實現的區別
實現方式避免了單繼承的侷限性,建議使用實現方式。
繼承Thread:執行緒程式碼存放在Thread子類run方法中。
實現Runnable,執行緒程式碼存放在介面子類的run方法中。


 執行緒的4種狀態


建立start() 執行sleep(time)時間到會自動執行;wait()等待notify()喚醒
凍結(睡眠和等待兩種)
消亡stop();或run方法結束。


特殊狀態:臨時狀態,阻塞 有執行資格CPU沒有給執行權。凍結沒有執行資格,結束凍結會先回到臨時狀態。


多執行緒中,由於阻塞狀態,多條語句操作同一個執行緒共享資料時,可能一個執行緒正在執行時產生阻塞,另一個執行緒也參與執行。導致出現安全隱患。


如何找到安全隱患
1,明確多執行緒執行的程式碼。
2,明確共享資料。
3,明確多執行緒執行程式碼中哪些語句是操作共享資料的。


解決辦法是,對多執行緒執行共享資料的語句,只能讓一個執行緒執行完。過程中不準別的參與。加鎖。
Java提供了專業解決方式。
就是同步程式碼塊
同步函式
函式要被物件呼叫,就會有個所屬物件引用,就是this,鎖是 this.
靜態同步函式被類呼叫,直接屬於類,鎖是 類名.class,型別是Class。
synchronized做為修飾符。
修飾符 修飾符 返回值型別 函式名()


死鎖
同步中巢狀同步,用的鎖不相同,就會產生死鎖。


synchronized(物件)//相當於一次只能完全執行一個執行緒,過程中不能執行其他執行緒。
{
需要被同步的程式碼
}


前提:
1,必須要有兩個或者多個以上的執行緒。
2,必須是多個執行緒使用同一個共享資料。
必須保證共同使用的共享資料要同步,就是隻執行一個執行緒。


解決了多執行緒的安全問題,但是由於需要判斷,較消耗資源。


static Thread curretThread():獲取當前執行緒物件。
getName():獲取執行緒名稱。
setName或者是建構函式可以用來設定執行緒名稱。

class Demo extends Thread//繼承Thread
{
	//複寫Thread類中的run方法
	public void run()
	{
		//自定義要執行緒執行的程式碼
		for(int x=1;x<10;x++)
			System.out.println("Demo run_"+x);
	}
}

class ThreadDemo
{
	public static void main(String[] args)
	{
	
		Demo d = new Demo();//建立好一個執行緒d.
		//d.start();//開啟d執行緒,並且執行其中的run方法。
		d.run();//只是呼叫了run方法,執行緒卻沒有執行,只建立了。
		
		for(int x=1;x<10;x++)
			System.out.println("main run_"+x);
	}
}

//賣票程式:多個視窗買票

class Ticket implements Runnable//實現Runnable介面	同步程式碼塊
{
	private int tick = 100;
	Object obj = new Object();
	public void run()//將執行緒要執行的程式碼存放在該run方法中
	{
		while(true)
		{	

			synchronized(obj)//同步程式碼塊
			{
				//多執行緒執行共享資料的語句
				if(tick>0)//由於臨時狀態,阻塞,多執行緒可能出現安全隱患

				{	
					System.out.println(Thread.currentThread().getName()+"..."+ tick--);
				}
			}
		}
	}
}

class Ticket implements Runnable//實現Runnable介面	同步函式
{
	private int tick = 100;

	public void run()
	{
		while(true)
		{	
			this.show();

		}
	}
	//由於臨時狀態,阻塞,多執行緒可能出現安全隱患
	public synchronized void show()//同步函式synchronized(this)
	{
		if(tick>0)
		{	

			System.out.println(Thread.currentThread().getName()+"..."+ tick--);
		}
	}
}

class TicketDemo
{
	public static void main(String[] args)
	{
		Ticket t = new Ticket();//建立Runnable介面的子類物件
		Thread t1 = new Thread(t);//Thread類建立執行緒物件,將Runnable介面的子類物件作為實際引數傳遞給Thread類的建構函式
		Thread t2 = new Thread(t);
		Thread t3 = new Thread(t);	
		t1.start();//呼叫Thread類的start方法開啟執行緒並呼叫Runnable介面子類的run方法
		t2.start();
		t3.start();	
	}
}


等待喚醒機制
wait();執行緒等待
notify();喚醒其他執行緒
notifyAll();喚醒全部執行緒


都使用在同步中,因為要對持有監視器(鎖)的執行緒操作,所以要用在同步中,只有同步才有鎖。


因為這些方法在操作同步執行緒時,都必須要標識它們所操作的執行緒共有的鎖,只有同一鎖上的被等待執行緒,可以被同一個鎖上notify喚醒。不同鎖的執行緒不能進行喚醒。就是隻能於相同鎖上才有效。
鎖可以是任意物件,因此能被任意物件呼叫的方法只能定義在Object類中。


if()notify()用於一對一執行緒。用於多對多時可能會覆蓋
while()notifyAll()用於多對多執行緒。while不用All會全部凍結。


JDK1.5中提供了多執行緒升級解決方案。將同步Synchronized替換成實現Lock操作。將Object中的wait,notify notifyAll,替換成了Condition物件,該物件可以Lock鎖,進行獲取。
可以喚醒不同鎖。相當於父類引用指向子類物件,多型的方法呼叫一樣。能夠喚醒指定的鎖。


停止執行緒
stop方法過時,只能run方法結束。
開啟多執行緒執行,執行程式碼通常是迴圈結構。控制住迴圈,就能讓run結束,關閉執行緒。
當執行緒處於凍結狀態時,不會讀到結束,不會結束執行緒。
沒有指定方式讓凍結的執行緒恢復到執行狀態時,需要清除凍結狀態,強制讓執行緒恢復到執行狀態中,就可以操作執行緒讓執行緒結束。
Thread類中提供了interrupt();方法。


守護執行緒
setDaemon
public final void setDaemon(boolean on)
t1.setDaemon(true);
將該執行緒標記為守護執行緒或使用者執行緒。當正在執行的執行緒都是守護執行緒時,Java 虛擬機器退出。該方法必須在啟動執行緒前呼叫。就是守護執行緒不能獨立執行。


Join
public final void join()
                throws InterruptedException
等待該執行緒終止。 
就是借用正在執行執行緒的執行權,結束了才交還執行執行緒。
用於臨時加入執行緒。


yield
public static void yield()暫停當前正在執行的執行緒物件,並執行其他執行緒。 
相當於放棄下執行權,不長期佔用。


toString
public String toString()返回該執行緒的字串表示形式,包括執行緒名稱、優先順序和執行緒組。一般誰開的執行緒就屬於哪個組。
setPriority
public final void setPriority(int newPriority)更改執行緒的優先順序。 (1到10分為1,5,10三等)

執行緒間通訊
多個執行緒操作同一個資源,操作動作不同(輸入輸出)。

class Res//要共用的資源
{
	private String name;
	private String sex;
	private boolean flag = false;//用來改變執行緒狀態
	public synchronized void set(String name,String sex)
	{
		if(flag)	//b函式上鎖是this
			try{this.wait();}catch(Exception e){}
		this.name = name;
		this.sex = sex;
		flag = true;
		this.notify();
	}
	public synchronized void out()
	{
		if(!flag)
			try{this.wait();}catch(Exception e){}
			//wait()有異常,實現介面中只能try
		System.out.println(name+"---"+sex);
		flag = false;
		this.notify();//喚醒執行緒
	}
}
//輸入操作執行緒
class Input implements Runnable
{
	private Res r;
	Input(Res r)
	{
		this.r = r;
	}
	public void run()
	{
		int x = 0;//定義輸入值
		while(true)
		{
			if(x==0)
				r.set("mini","man");
			else
				r.set("一一","女");
			x = (x+1)%2;
		}
	}
}
//輸出操作執行緒
class Output implements Runnable
{
	private Res r;
	Output(Res r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.out();
		}
	}
}

class InputOutputDemo
{
	public static void main(String[] args)
	{
		//建立共用操作物件
		Res r = new Res();
		//使用匿名物件開啟執行緒
		new Thread(new Input(r)).start();
		new Thread(new Output(r)).start();
	}
}

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