1. 程式人生 > >Java——多執行緒基本使用(三) 餓漢式和懶漢式的單例設計模式,多執行緒之間的通訊

Java——多執行緒基本使用(三) 餓漢式和懶漢式的單例設計模式,多執行緒之間的通訊

這一則部落格主要寫的是單例設計模式,與實現多執行緒之間的通訊等等~

1.單例設計模式:保證類在記憶體中只有一個物件

2.保證類在記憶體中只有一個物件

             (1)控制類的建立,不讓其他類來建立本類的物件。用private私有構建函式

             (2)在本類中定義一個本類的物件。

             (3)提供公共的訪問形式

3.單例寫法

             (1)餓漢式

             (2)懶漢式

             (3)直接用final修飾 (private static final Single3 s=new Single3();)

             餓漢式與懶漢式的區別:

             (1)餓漢式是空間換時間,懶漢式是時間換空間

             (2)在多執行緒訪問時,餓漢式不會建立多個物件,懶漢式有可能會建立多個物件

4.Runtime類:

使用了單例設計模式,是一個單例類

5.Timer類(計時器):一種工具,執行緒用其安排以後在後臺執行緒中執行的任務。可安排任務執行一次,或者定期重複執行

             schedule(TimeTask task,Date time),安排在指定的時間執行指定的任務

t.schedule(new MyTimerTask(), new Date(118,9,11,18,52,50),3000);  安排指定任務在指定時間開始進行重複的固定延遲執行

第一個引數是安排的任務,第二個引數是執行時間,第三個引數是過多長時間再重複執行

6.兩個執行緒間的通訊

             什麼時候需要通訊?

             在多個執行緒併發執行時,在預設情況下cpu是隨機切換執行緒的;如果我們希望它們有規律的執行,就可以使用通訊,例如每一次執行緒執行一次列印

             如何進行通訊?

             如果希望執行緒等待,就呼叫wait();如果希望喚醒等待的執行緒,就呼叫notify();這兩個方法必須再同步程式碼中執行,並且使用同步鎖物件來呼叫

             wait(),notify()和notifyAll()方法

7.三個或三個以上間的執行緒通訊

             (1)notify()方法是隨機喚醒一個執行緒

             (2)notifyAll()方法是喚醒所有執行緒

        如果多個執行緒之間通訊,需要使用notifyAll()通知所有執行緒,用while來反覆判斷條件

8.執行緒之間通訊需要注意的問題

             (1)在同步程式碼塊中,用哪個物件鎖就用哪個物件呼叫wait()方法

             (2)因為鎖物件可以是任意物件,且Object類是所有類的基類所有將wait()和notify()方法定義在Object類中

             (3)sleep方法和wait方法的區別

                    1)sleep方法必須傳入引數,引數是時間,時間道理自動醒來;wait方法可以傳入引數,在引數的時間結束後等待,                      不傳入引數就是直接等待

                    2)sleep方法在同步函式或同步程式碼塊中不釋放鎖;wait方法在同步函式或者同步程式碼塊中,釋放鎖

9.互斥鎖

             (1)同步:使用ReentrantLock類的lock()和unlock()方法進行同步

             (2)通訊

                    1)使用ReentrantLock類的newCondition()方法可以獲取Condition物件(使用await與signal方法)

                    2)需要等待的時候使用Condition的await()方法,喚醒的時候使用signal()方法

                    3)不同的執行緒使用不同的Condition,這樣就能區分喚醒的時候找哪個執行緒

 

 

在執行下面測試程式碼中,可以一個案例一個案例執行,因為會有可能會出一些問題,比如說前面的死迴圈無法執行下一個例子要實現的函式等等....

package pra_21;
import java.io.IOException;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class J_40 {

	/**
	 * @param args
	 * @throws IOException 
	 * @throws InterruptedException 
	 */
	public static void main(String[] args) throws IOException, InterruptedException {
		/*
		//1.單例設計模式
		//Single s1=new Single();
		//Single s2=Single.s;			//成員變數被私有,不能通過類名點去呼叫,解決了呼叫改變類的成員變數s
		Single s3=Single.getS();
		Single s4=Single.getS();		//此時不能修改
		System.out.println(s3==s4);
		
		//2.Runtime類
		Runtime rt=Runtime.getRuntime();		//獲取執行是物件
		//在單獨的程序中執行指定的字串命令
		//rt.exec("shutdown -s -t 300"); 										
		//rt.exec("shutdown -a");
		
		//3.Timer類
		
		Timer t=new Timer();		//建立計時器
		t.schedule(new MyTimerTask(), new Date(118,9,11,18,52,50));//安排指定時間執行指定任務
			//第一個引數是安排的任務,第二個引數是執行時間,第三個引數是過多長時間再重複執行
		//t.schedule(new MyTimerTask(), new Date(118,9,11,18,52,50),3000);//安排指定任務在指定時間開始進行重複的固定延遲執行
		while(true){
			Thread.sleep(1000);
			System.out.println(new Date());
		}
		*/
		//4.兩個執行緒之間的通訊
			//等待喚醒機制
		final Pr2 p2=new Pr2();
		new Thread(){
			public void run(){
				while(true){
					try {
						p2.pri();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		new Thread(){
			public void run(){
				while(true){
					try {
						p2.pri2();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		//5.多個執行緒之間的通訊
		final Pr3 p3=new Pr3();
		new Thread(){
			public void run(){
				while(true){
					try {
						p3.pri();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		new Thread(){
			public void run(){
				while(true){
					try {
						p3.pri2();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		new Thread(){
			public void run(){
				while(true){
					try {
						p3.pri3();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		//9.互斥鎖
		final Pr3 pr4=new Pr3();
		new Thread(){
			public void run(){
				while(true){
					try {
						pr4.pri();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		new Thread(){
			public void run(){
				while(true){
					try {
						pr4.pri2();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		new Thread(){
			public void run(){
				while(true){
					try {
						pr4.pri3();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();

	}
}
//餓漢式寫法,看法常用
class Single{
	//1.私有構造方法,其他類不能訪問該構造方法
	private Single(){}
	//2.建立本類物件
	private static Single s=new Single();	//如果是非靜態的成員變數就只能用物件名點去呼叫,加了靜態以後可以用類名點,但是被私有就不行
	//3.對外提供公告的訪問方法(get set方法),主要是不讓其改變s的值
	public static Single getS(){					//獲取物件(例項)
		return s;
	}
}
//懶漢式,單例的延遲載入模式,會出現多執行緒不安全的問題
class Single2{
	//1.私有構造方法,其他類不能訪問該構造方法
	private Single2(){}
	//2.宣告引用
	private static Single2 s;	//
	//3.對外提供公告的訪問方法(get set方法)
	public static Single2 getS(){					//獲取物件(例項)
		if(s==null){
			s=new Single2();
		}
		return s;
	}
}
//第三種
class Single3{
	//1.私有構造方法,其他類不能訪問該構造方法
	private Single3(){}
	//2.宣告引用
	private static final Single3 s=new Single3();	//直接用final修飾,使其不能不改變
}
//Timer
class MyTimerTask extends TimerTask{

	@Override
	public void run() {
		System.out.println("走你!");
	}

}
//等待喚醒機制:兩個方法 wait(),notify()方法,notifyAll()方法
class Pr2{
	private int flag=1;
	public void pri() throws InterruptedException{
		synchronized(this){
			if(flag!=1){
				this.wait();			//當前執行緒等待
			}
			System.out.print("p");
			System.out.print("q");
			System.out.print("r");
			System.out.print("s");
			System.out.print("1");
			System.out.println();
			flag=2;
			this.notify(); 				//隨機喚醒單個等待執行緒
		}		
	}
	public void pri2() throws InterruptedException{
		synchronized(this){
			if(flag!=2){
				this.wait();
			}
			System.out.print("a");
			System.out.print("b");
			System.out.print("c");
			System.out.print("d");
			System.out.print("2");
			System.out.println();
			flag=1;
			this.notify();
		}
	}
}
//多個執行緒
class Pr3{
	private int flag=1;
	public void pri() throws InterruptedException{
		synchronized(this){
			while(flag!=1){
				this.wait();			//當前執行緒等待
			}
			System.out.print("p");
			System.out.print("q");
			System.out.print("r");
			System.out.print("s");
			System.out.print("1");
			System.out.println();
			flag=2;
			this.notifyAll(); 				//隨機喚醒單個等待執行緒
		}		
	}
	public void pri2() throws InterruptedException{
		synchronized(this){
			while(flag!=2){
				this.wait();
			}
			System.out.print("a");
			System.out.print("b");
			System.out.print("c");
			System.out.print("d");
			System.out.print("2");
			System.out.println();
			flag=3;
			this.notifyAll();
		}
	}
	public void pri3() throws InterruptedException{
		synchronized(this){
			while(flag!=3){
				this.wait();			//執行緒3再此等待,if語句是在哪裡等待,就在哪裡起來,while則可以
										//while迴圈是迴圈判斷,每一次都會判斷標記
			}
			System.out.print("u");
			System.out.print("i");
			System.out.print("o");
			System.out.print("p");
			System.out.print("3");
			System.out.println();
			flag=1;
			this.notifyAll();
		}
	}
}
//使用互斥鎖實現多執行緒
class Pr4{
	private ReentrantLock r=new ReentrantLock();
	private Condition c1=r.newCondition();
	private Condition c2=r.newCondition();
	private Condition c3=r.newCondition();
	private int flag=1;
	public void pri() throws InterruptedException{
			r.lock();					//獲取鎖
			if(flag!=1){
				c1.await();			//當前執行緒等待
			}
			System.out.print("p");
			System.out.print("q");
			System.out.print("r");
			System.out.print("s");
			System.out.print("1");
			System.out.println();
			flag=2;
			c2.signal();
			r.unlock();				//釋放鎖
		}		
	public void pri2() throws InterruptedException{
			r.lock();
			if(flag!=2){
				c2.await();
			}
			System.out.print("a");
			System.out.print("b");
			System.out.print("c");
			System.out.print("d");
			System.out.print("2");
			System.out.println();
			flag=3;
			c3.signal();
			r.unlock();	
		}
	public void pri3() throws InterruptedException{
			r.lock();
			if(flag!=3){
				c3.await();
			}
			System.out.print("u");
			System.out.print("i");
			System.out.print("o");
			System.out.print("p");
			System.out.print("3");
			System.out.println();
			flag=1;
			c1.signal();
			r.unlock();
	}
}