1. 程式人生 > >JavaSE基礎學習筆記及案例(二)多執行緒(下)與簡單工廠模式的瞭解

JavaSE基礎學習筆記及案例(二)多執行緒(下)與簡單工廠模式的瞭解

1.多執行緒(下)

1.1單例設計模式:保證類在記憶體中只存在一個物件
************餓漢式與懶漢式的區別【面試題】

  1. 餓漢式單例模式:以空間換時間
  2. 懶漢式單例模式:以時間換空間(不推薦使用,僅在面試中用到)
    3.多執行緒訪問時:餓漢式不會建立多個物件;而懶漢式模式有可能會建立多個物件【弊端】
/* @author ZHENG
 *	餓漢式
*/
class Singleton{
	//1.私有構造方法,其他類不能訪問該構造方法
	private Singleton(){
		
	}
	//2.建立本類物件(私有成員變數)
	private static Singleton s = new Singleton();
	//3.對外提供公共的訪問方法
	public static Singleton getInstance(){
		return s;
	}
}
/**
 * @author ZHENG
 *	懶漢式:單例延遲載入模式
 */
class Singleton{
	//1.私有構造方法,其他類不能訪問該構造方法
	private Singleton(){
		
	}
	//2.宣告一個引用
	private static Singleton s;
	//3.對外提供公共的訪問方法
	public static Singleton getInstance(){
		if(s==null){
			//執行緒1等待,執行緒2等待
			s=new Singleton();
		}
		return s;
	}
}

1.2第三種單例設計模式
非重點

class Singleton{
	//1.私有構造方法,其他類不能訪問該構造方法
	private Singleton(){
		
	}
	//2.宣告一個引用
	public final static Singleton s=new Singleton();
	
}

1.3多執行緒之RunTime類(瞭解)

public class demo2_Runtime {
	public static  void main(String[] args) throws IOException{
		Runtime r = Runtime.getRuntime();//獲取執行時物件
		/*r.exec("shutdown -s -t 300");//設定電腦5分鐘後關機
*/		r.exec("shutdown -a");
	}
}

1.4多執行緒之Timer類
Timer:一種計時器
TimerTask:建立一個計時器任務

t.schedule(安排的任務,new Date(當前年份-1900,月,日,時,分,秒),多長時間重複執行) //指定時間執行指定的任務

/**
 * @author ZHENG
 *	timer指定時間安排指定任務
 */
public class demo3_Timer {
	public static void main(String[] args) throws InterruptedException{
		Timer t = new Timer();
		//指定時間安排指定任務
		//t.schedule(安排的任務,new Date(當前年份-1900,月,日,時,分,秒),多長時間重複執行)
		//2018年11月3日
		t.schedule(new MyTimerTask(), new Date(118,10,3,19,39,10), 3000);
		while(true){
			Thread.sleep(1000);
			System.out.println(new Date());
		}
	}
}
class MyTimerTask extends TimerTask{
	@Override
	public void run() {
		System.out.println("起床了...");
	}
}

1.5多執行緒之執行緒之間的通訊
-------wait方法:其他物件呼叫此物件的notify,導致當前執行緒等待
-------notify:兩個執行緒間的通訊:喚醒等待的單個執行緒
-------notifyAll:多個執行緒間的通訊:喚醒所有執行緒
注意事項:1.在同步程式碼塊中,用哪個物件鎖,就用哪個物件呼叫wait方法;
2.sleep方法和wait方法區別?
—2.1.sleep必須傳入時間引數,時間到了自動醒來;
wait既可以傳入引數,也可以不傳入引數,如果傳入引數就是在引數時間結束後等待,若不傳入引數就是直接等待;
—2.2.sleep方法在同步函式或同步程式碼塊中,不釋放鎖;
wait方法在同步函式或者同步程式碼塊中釋放鎖;
以下程式碼為兩個執行緒之間的通訊
同步程式碼塊使用if判斷

public class demo4_notify {
	/**
	 * @param args
	 * 
	 * 等待喚醒機制
	 */
	public static void main(String[] args){
		final Print p = new Print();
		while(true){
			new Thread(){
				public void run(){
					try {
						p.print1();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}.start();
			new Thread(){
				public void run(){
					try {
						p.print2();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}.start();
		}
	}
}
class Print{
	private int flag = 1;
	public void print1() throws InterruptedException{
		//非靜態程式碼塊使用this
		synchronized (this) {
			if(flag != 1){
				this.wait();//當前執行緒等待
			}
			System.out.print("好");
			System.out.print("好");
			System.out.print("學");
			System.out.print("習");
			System.out.println();
			flag = 2;
			this.notify();//隨機喚醒單個等待的執行緒
		}
	}
	public void print2() throws InterruptedException{
		//非靜態程式碼塊使用this
		synchronized (this) {
			if(flag != 2){
				this.wait();//當前執行緒等待
			}
			System.out.print("天");
			System.out.print("天");
			System.out.print("向");
			System.out.print("上");
			System.out.println();
			flag = 1;
			this.notify();//隨機喚醒單個等待的執行緒
		}
	}
}

以下程式碼為多個執行緒間通訊,程式碼塊中使用while判斷

public class demo5_notifyAll {


	/**
	 * @param args
	 * 三條執行緒呼叫三個方法:使用while
	 * 等待喚醒機制
	 */
	public static void main(String[] args){
		final PrintAll p = new PrintAll();
		while(true){
			new Thread(){
				public void run(){
					try {
						p.print1();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}.start();
			new Thread(){
				public void run(){
					try {
						p.print2();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}.start();
			new Thread(){
				public void run(){
					try {
						p.print3();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}.start();
		}
	}
}
class PrintAll{
	private int flag = 1;
	public void print1() throws InterruptedException{
		//非靜態程式碼塊使用this
		synchronized (this) {
			while(flag != 1){
				this.wait();//當前執行緒等待
			}
			System.out.print("好");
			System.out.print("好");
			System.out.print("學");
			System.out.print("習");
			System.out.println();
			flag = 2;
			this.notifyAll();//隨機喚醒所有等待的執行緒
		}
	}
	public void print2() throws InterruptedException{
		//非靜態程式碼塊使用this
		synchronized (this) {
			while(flag != 2){
				this.wait();//當前執行緒等待
			}
			System.out.print("天");
			System.out.print("天");
			System.out.print("向");
			System.out.print("上");
			System.out.println();
			flag = 3;
			this.notifyAll();//隨機喚醒所有等待的執行緒
		}
	}
	public void print3() throws InterruptedException{
		//非靜態程式碼塊使用this
		synchronized (this) {
			while(flag != 3){
				this.wait();//當前執行緒等待
			}
			System.out.print("-");
			System.out.print("毛");
			System.out.print("主");
			System.out.print("席");
			System.out.println();
			flag = 1;
			this.notifyAll();//隨機喚醒所有等待的執行緒
		}
	}
}

1.6多執行緒之互斥鎖
-----------ReentrantLock:建立互斥鎖>>>>>>>>>>ReentrantLock r = new ReentrantLock
----r.lock:獲取鎖
----r.unlock:釋放鎖

private ReentrantLock r = new ReentrantLock();//互斥鎖
	private Condition c1 = r.newCondition();//建立3個監視器
	private Condition c2 = r.newCondition();
	private Condition c3 = r.newCondition();

對1.5由synchronized實現的多個執行緒間通訊優化(1.5特性)

public class demo1 {
	public static void main(String[] args){
		final PrintAll p = new PrintAll();
		while(true){
			new Thread(){
				public void run(){
					try {
						p.print1();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}.start();
			new Thread(){
				public void run(){
					try {
						p.print2();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}.start();
			new Thread(){
				public void run(){
					try {
						p.print3();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}.start();
		}
	}
	}
class PrintAll{
	private ReentrantLock r = new ReentrantLock();//互斥鎖
	private Condition c1 = r.newCondition();//建立3個監視器
	private Condition c2 = r.newCondition();
	private Condition c3 = r.newCondition();
	private int flag = 1;
	public void print1() throws InterruptedException{
		r.lock();//獲取鎖
				if(flag != 1){
				c1.await();//c1等待
			}
			System.out.print("好");
			System.out.print("好");
			System.out.print("學");
			System.out.print("習");
			System.out.println();
			flag = 2;
			c2.signal();//喚醒c2
		r.unlock();//釋放鎖
	}
	public void print2() throws InterruptedException{
		r.lock();
			if(flag != 2){
				c2.await();
			}
			System.out.print("天");
			System.out.print("天");
			System.out.print("向");
			System.out.print("上");
			System.out.println();
			flag = 3;
			c3.signal();
		r.unlock();
	}
	public void print3() throws InterruptedException{
		r.lock();
			if(flag != 3){
				c3.await();;
			}
			System.out.print("-");
			System.out.print("毛");
			System.out.print("主");
			System.out.print("席");
			System.out.println();
			flag = 1;
			c1.signal();
		r.unlock();
	}
}

1.7多執行緒的5種狀態【面試題】
在這裡插入圖片描述
1.8執行緒池
1.建立兩個執行緒池
ExecutorService pool = Executors.newFixedThreadPool(2);

2.工廠模式【瞭解】

2.1簡單工廠設計模式【瞭解】
第一步:建立一個抽象的Animal類

public abstract class Animal {

	public abstract void eat();
}

第二步:建立貓和狗類物件繼承自Animal類

public class Cat extends Animal {

	@Override
	public void eat() {
		System.out.println("貓吃魚");
	}

}

public class Dog extends Animal {

	@Override
	public void eat() {
		System.out.println("狗吃肉");
	}
}

第三步建立Animal的工廠類

public class Animal_Fac {
	public static Animal creatAnimal(String name){
		if("dog".equals(name)){
			return new Dog();
		}else if("cat".equals(name)){
			return new Cat();
		}else{
			return null;
		}
	}
}

第四步:建立測試類實現簡單工廠模式

public class Test {
	public static void main(String[] args){
		Dog cd = (Dog) Animal_Fac.creatAnimal("dog");
		cd.eat();
		Animal ct = Animal_Fac.creatAnimal("cat");
		ct.eat();
	}
}

2.2工廠方法
第一步:建立動物抽象類,dog類與cat類分別繼承該抽象類,步驟如1.9前三步;
第二步:建立工廠介面

/**
 * @author ZHENG
 *	工廠介面
 */
public interface Fac_Inter {
	public Animal creatAnimal();
}

第三步:分別建立Cat工廠和Dog工廠實現第二步中動物工廠介面

public class Cat_Fac implements Fac_Inter {
	@Override
	public Animal creatAnimal() {
		return new Cat();
	}
}
public class Dog_Fac implements Fac_Inter {
	@Override
	public Animal creatAnimal() {
		return new Dog();
	}
}

第四步:建立測試類,實現程式碼

public class Test {

	public static void main(String[] args) {
		Cat_Fac cf = new Cat_Fac();/*與建立狗工廠方法相同*/
		Dog_Fac df = new Dog_Fac();//建立狗工廠物件
		Dog d = (Dog) df.creatAnimal();//呼叫方法,向下強轉,得狗物件
		d.eat();//狗物件呼叫方法
	}
}

2.3介面卡設計模式
介面卡原理:
1.介面卡就是一個類實現監聽介面,所有抽象方法都被重寫,但是方法是空的;
2.介面卡需要定義成抽象的,因為建立該類物件,呼叫空方法無意義;
3.目的:簡化操作,定義監聽器時繼承介面卡,僅重寫需要的方法即可;

public class shipeiqi {
	public static void main(String[] args){
		
	}
}
interface 和尚{
	public void 打坐();
	public void 唸經();
	public void 撞鐘();
	public void 習武();
}
/**
 * 該類即是介面卡類
 * 
 * 宣告成抽象的,防止其他類呼叫水滸傳裡的方法,因為建立也無意義,方法都是空的
 */
abstract class 水滸傳 implements 和尚{

	@Override
	public void 打坐() {
		
	}

	@Override
	public void 唸經() {
		
	}

	@Override
	public void 撞鐘() {
		
	}

	@Override
	public void 習武() {
		
	}
	
}
/**
 * 魯智深僅有習武這個方法
 * 
 * 如果唐僧實現和尚這個介面,可以通過介面卡,需要哪個方法就重寫哪個方法
  */
class 魯智深 extends 水滸傳{
	public void 習武(){
		System.out.println("倒拔垂楊柳");
		System.out.println("拳打鎮關西");
		System.out.println("......");
	}
}

2.4設計模式之模板(Template)

public class demo2 {
	public static void main(String[] args){
		Demo d = new Demo();
		System.out.println(d.getTime());
	}
}
/**
 * @author 
 *	模板:定義一個框架模型,如需改動更改子類即可
 */
abstract class GetTime{
	public final long getTime(){//子類不可更改該方法
		long start = System.currentTimeMillis();
		code();
		long end = System.currentTimeMillis();
		return (end-start)/1000;
	}
	public abstract void code();//讓子類可以重寫該方法
}
class Demo extends GetTime{
	@Override
	public void code() {
		for (int i = 0; i < 100000; i++) {
			System.out.println(i);
		}
	}
}