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培訓、期待與您交流! ----------