1. 程式人生 > >黑馬程式設計師_java多執行緒

黑馬程式設計師_java多執行緒

          多執行緒

1    建立執行緒

       方式一:繼承Thread類,覆蓋run方法。

           步驟:1、定義類繼承Thread。

                        2、複寫Thread類中的run方法。

                        3、呼叫執行緒的start方法,該方法兩個作用:啟動執行緒,呼叫run方法。

package cn.itcast.thread;


//寫一個類繼承Thread,模擬單執行緒的
class Demo extends Thread{
	Demo(String name){
		super(name);
	}
	public void run(){
		for(int x = 0 ; x < 10;x++){
			System.out.println("demoRun..."+x+getName());
		}
	}
}

public class ThreadDemo {
	public static void main(String[] args){
		Demo d = new Demo("旺財");
		d.start();
		for(int x = 0 ; x < 10 ; x++){
			System.out.println("main..."+x+Thread.currentThread().getName());
		}
	}
}

      發現執行結果每次都不同。

                因為多個執行緒都獲得cpu的執行權,cpu執行到誰,誰就執行。

       明確一點,在某一個時刻,只能有一個執行緒在執行,cpu咋做著快速的切換,已達到看上去是同時執行的效果。

       我們可以形象把多執行緒的執行行為在互相搶奪cpu的執行權。

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

      為什麼要覆蓋run方法呢?

            Thread類用於描述執行緒。該類就定義了一個功能,用於儲存執行緒要執行的程式碼,該儲存功能就是run方法。

            也就是說Thread類中的run方法,用於儲存執行緒要執行的程式碼。

             執行緒預設名稱,this.getName(),是從0開始。

用繼承Thread的建立多執行緒模擬售票

package cn.itcast.thread;
/*
 * 利用多執行緒,實現模擬多視窗同時售票
 */

//定義類,票,模擬售票
class Ticket extends Thread{
	private static int tickets = 100;
	Object obj = new Object();
	public void run(){
		while(true){
			synchronized (obj) {
				
			
				if(tickets>0){
					try{
					Thread.sleep(5);
					}catch(Exception e){}
					System.out.println(getName()+"..出售第"+tickets--+"張票");
				}
			}
		}
	}
}
public class TicketDemo {
	public static void main(String[] args) {
		Ticket t1 = new Ticket();
		Ticket t2 = new Ticket();
		Ticket t3 = new Ticket();
		Ticket t4 = new Ticket();
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}

     方式二:實現Runable介面

      步驟:1,定義類實現Runable介面。

                   2,覆蓋Runable介面中的run方法。

                   3,通過Thread類建立執行緒物件。

                   4,將Runable介面的子類物件作為實際引數傳遞給Thread的建構函式。

                   5,呼叫Thread類的start方法開啟執行緒並呼叫Runable介面子類的run方法。

package cn.itcast.thread;


//寫一個類實現Runnable,模擬單執行緒的
class Demo implements Runnable{
	
	public void run(){
		for(int x = 0 ; x < 10;x++){
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("demoRun..."+x);
		}
	}
}

public class ThreadDemo {
	public static void main(String[] args){
		Demo d = new Demo();
		Thread t = new Thread(d);
		t.start();
		for(int x = 0 ; x < 10 ; x++){
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("main..."+x+Thread.currentThread().getName());
		}
	}
}


實現方式和繼承方式有什麼不同?

       實現方式的好處:避免了單繼承的侷限性。在定義執行緒時,建議使用實現方式。

      繼承Thread:執行緒程式碼存放Thread子類run方法中。

       實現Runable,執行緒程式碼存在介面的子類的run方法中。

執行緒的五種狀態:

    建立:start()

    臨時阻塞:CPU在執行某個執行緒時,其它執行緒都不會執行,具備執行資格,但是沒有執行權

    凍結:sleep()wait(),時間到notify()

    執行:run()stop()

    消亡:run()方法結束

    sleep()需要指定睡眠時間,單位是毫秒;

    特殊的狀態:臨時阻塞。具備了執行資格,但是還沒有獲取資源;

2    解決執行緒安全問題

      解決原理:讓多條操作共享資料的程式碼在某一時間段被一個執行緒執行,執行過程中其它執行緒不參與運算;

          同步程式碼塊: synchronized(物件) {

需要同步的程式碼;

}

將訪問資料的程式碼鎖住,在同步程式碼塊中的內容同一時間內只能一個執行緒執行;

同步可以解決安全問題的根本原因就在那個物件上;該物件如同鎖的功能;

          同步方法:方法上加synchronized,整個方法的程式碼都是同步的,只能一個執行緒執行,同步方法使用this作為鎖;

      同步的前提:要兩個或者兩個以上的執行緒;多個執行緒使用的是同一個鎖;

      同步的好處:同步的出現解決了多執行緒的安全問題;

      同步的弊端:當執行緒相當多時,每個執行緒都會去判斷同步上的鎖耗費資源,降低程式的執行效率;

      死鎖:在多個執行緒併發執行使用多個鎖來同步時,有可能互相沖突,導致程式無法繼續執行(同步巢狀);

    同步出現解決了執行緒安全問題,但是非常消耗資源,效率會降低並且容易引發死鎖;

3   執行緒間通訊

      在同步程式碼中可以使用鎖物件的wait()方法讓當前執行緒等待;

      使用鎖物件的notify()方法可以將正在等待的執行緒喚醒;

      如果多個執行緒都在等待,notify()喚醒隨機1個;

      notifyAll()方法可以喚醒所有在等待的執行緒;

      wait(),notify(),notifyAll(),這些用來操作執行緒存在與同步中,使用這些方法時必須要標識所屬的同步的鎖,

  鎖可以是任意物件,所以任意物件呼叫的方法一定定義Object類中;

      wait(),sleep()區別:

          wait():釋放cpu執行權,釋放鎖;

  sleep():釋放cpu執行權,不釋放鎖;

4    JDK5之後的執行緒同步與通訊

  同步:

 使用java.util.concurrent.locks.Lock介面的實現類物件來進行同步;

  ReentrantLock就是Lock的實現類,可以實現synchronized的功能;

  在需要同步的程式碼塊前後使用lock()unlock()方法來完成同步;

 unlock()最好放在finally中,因為如果上面程式碼丟擲異常沒有解鎖;,會導致其它執行緒無法執行,程式卡死;

   通訊:

   使用Lock物件的newCondition()方法獲取一個Condition物件,Condition物件可以控制指定執行緒的等待與喚醒;

     await()方法可以控制執行緒等待;

     signal()方法可以喚醒等待的執行緒;

     signalAll()方法可以喚醒所有等待執行緒;

5  停止執行緒

      定義迴圈結束標記:因為執行緒執行程式碼一般都是迴圈,只要控制了迴圈即可;

      使用interrupt()中斷:該方法是結束執行緒的凍結狀態,使執行緒回到執行狀態中來;

      注:stop()已經過時不再使用;

6    執行緒中方法

      currentThread():靜態方法,返回當前執行緒物件的引用;

      getName(),setName():用來獲取、設定當前執行緒的名字;

      sleep():控制執行緒休眠,單位為毫秒;

      setDaemon():將執行緒設定為守護執行緒。執行緒預設是非守護執行緒,守護執行緒不能單獨執行;

      join():讓出執行權,當前執行緒暫停,等待加入的執行緒執行結束,當前執行緒再執行;

      setPriority(int num):設定執行緒優先順序;

      toString():返回該執行緒的字串表示形式,包括執行緒名稱、優先順序和執行緒組;

      Thread(String name):建構函式,執行緒物件一建立就可以指定名稱;

      setName(String name):自定義執行緒名字


        ------- android培訓java培訓java學習型技術部落格期待與您交流! ----------