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();
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章