JAVA執行緒總結( 二)
阿新 • • 發佈:2018-11-20
繼續上篇的總結,這次我們講執行緒同步機制
執行緒同步是為了確保執行緒安全,所謂執行緒安全指的是多個執行緒對同一資源進行訪問時,有可能產生資料不一致問題,導致執行緒訪問的資源並不是安全的。如果多執行緒程式執行結果和單執行緒執行的結果是一樣的,且相關變數的值與預期值一樣,則是執行緒安全的。
舉個簡單的例子,後邊會寫到這個例子,鐵路售票,分四個視窗賣,一共一百張,需要同步。
執行緒同步機制包括同步程式碼塊和同步方法兩種。
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();
}