1. 程式人生 > >JAVA執行緒總結( 二)

JAVA執行緒總結( 二)

繼續上篇的總結,這次我們講執行緒同步機制

執行緒同步是為了確保執行緒安全,所謂執行緒安全指的是多個執行緒對同一資源進行訪問時,有可能產生資料不一致問題,導致執行緒訪問的資源並不是安全的。如果多執行緒程式執行結果和單執行緒執行的結果是一樣的,且相關變數的值與預期值一樣,則是執行緒安全的。

舉個簡單的例子,後邊會寫到這個例子,鐵路售票,分四個視窗賣,一共一百張,需要同步。

執行緒同步機制包括同步程式碼塊和同步方法兩種。

1.同步程式碼塊

package com.tao.syn;

public class Demo1_Synchronized {
	public static void main(String[] args) {
		final Printer p=new Printer();
		new Thread(){
			public void run(){
				for(int i=1;i<100;i++){
					p.print1();
				}
			}
		}.start();
		
		new Thread(){
			public void run(){
				for(int i=1;i<100;i++){
					p.print2();
				}
			}
		}.start();
	}

}
class Demo{
	
}
class Printer {
	Demo d=new Demo();
	public void print1(){
		synchronized (d) {             //同步程式碼塊,鎖機制,鎖物件可以是任意的
			System.out.print("清");
		System.out.print("華");
		System.out.print("大");
		System.out.print("學");
		System.out.println();
		}	
	}
	public void print2(){
		synchronized (d) {        //	synchronized (new Demo())不可行,因為不是同一物件了      
			System.out.print("我");
		System.out.print("愛");
		System.out.print("你");
		System.out.println();
		}
		
	}
}

2.同步方法

package com.tao.syn;

public class Demo2_Synchronized {
	/*
	        非靜態的同步方法的鎖物件是神馬?
		答:非靜態的同步方法的鎖物件是this 
		靜態的同步方法的鎖物件是什麼?
		是該類的位元組碼物件
	 */
	public static void main(String[] args) {
		final Printer p=new Printer();
		new Thread(){
			public void run(){
				for(int i=1;i<1000;i++){
					p.print1();
				}
			}
		}.start();
		
		new Thread(){
			public void run(){
				for(int i=1;i<1000;i++){
					p.print2();
				}
			}
		}.start();
	}

}
class Demo2{
	
}
class Printer2 {
	Demo d=new Demo();
	public static synchronized void print1(){
		System.out.print("清");
		System.out.print("華");
		System.out.print("大");
		System.out.print("學");
		System.out.println();	
	}
	public static void print2(){
		synchronized (Printer2.class) {        //	synchronized (new Demo())不可行,因為不是同一物件了      
			System.out.print("我");
		System.out.print("愛");
		System.out.print("你");
		System.out.println();
		}
		
	}
}
鐵路賣票的例子
package com.tao.syn;
/**
 * 
 * @author 天外飛星
 * 鐵路賣票,四個視窗,一共100張
 *
 */
public class Demo3_Ticket {
	public static void main(String[] args) {
		new Ticket().start();    //開啟四條執行緒,即四個視窗
		new Ticket().start();
		new Ticket().start();
		new Ticket().start();
	}
}	
class Ticket extends Thread{
	private static int ticket=100;    //必須設定為static的,四個執行緒共享ticket
	public void run(){
		while(true){
			synchronized (Ticket.class) {    //只能class,因為使用物件的話,每個Ticket都會建立一個
				if(ticket==0){
				try {
					Thread.sleep(10); 
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				break;
			}
			}		
			System.out.println("賣第"+ticket--+"張票");
		}
	}
}

單例設計模式

單例模式,是一種常用的軟體設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中,應用該模式的類一個類只有一個例項。即一個類只有一個物件例項。

具體實現

需要:

(1)將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。

(2)在該類內部產生一個唯一的例項化物件,並且將其封裝為private static型別。

(3)定義一個靜態方法返回這個唯一物件。

實現一:立即載入 / “餓漢模式”
package com.tao.thread;

public class Demo2_Singleton1 {
	public static void main(String[] args) {
		Singleton1 s2 = Singleton1.getInstance();
		// Singleton.s1=null;
		Singleton1 s3 = Singleton1.getInstance();
		System.out.println(s2 == s3);
	}
}

class Singleton1 {
	// 1.私有構造方法,其他類不能訪問該類構造方法
	private Singleton1() {
	};

	/*
	 * 一、餓漢式(常用)
	 */
	// 2.建立本類物件
	private static Singleton1 s1 = new Singleton1();

	// 3.對外提供公共的訪問方法
	public static Singleton1 getInstance() { // 獲取例項
		return s1;
	}
}
實現二:延遲載入 / “懶漢模式”
package com.tao.thread;

public class Demo3_Singleton2 {
	public static void main(String[] args) {
		Singleton2 s2 = Singleton2.getInstance();
		// Singleton.s1=null;
		Singleton2 s3 = Singleton2.getInstance();
		System.out.println(s2 == s3);
	}
}

class Singleton2 {
	// 1.私有構造方法,其他類不能訪問該類構造方法
	private Singleton2() {
	};

	/*
	 * 二、懶漢式
	 */
	// 2.建立本類物件
	private static Singleton2 s1;
	public static Singleton2 getInstance(){		
		if(s1==null){ 
			//執行緒1等待,執行緒2等待可能會導致建立兩個物件 ,平時不用,面試用
			s1=new Singleton2();
		}
		return s1;
	}
}

實現三、final修飾方法

package com.tao.thread;
/**
 *  三、final修飾方法
 * @author 天外飛星

 *
 */
public class Demo4_Singleton3 {
	public static void main(String[] args) {
		Singleton4 s2=Singleton4.s1;     //	 成員變數被私有,不能通過類名.呼叫
	//	Singleton4 s1=null;																	
		Singleton4 s3=Singleton4.s1;  
		System.out.println(s2==s3);
	}
	
}
class Singleton4{
		//1.私有構造方法,其他類不能訪問該類構造方法
		private Singleton4(){};
		static final Singleton4 s1=new Singleton4();
		
		
}