【多線程】5.多線程零散知識點(單例、線程狀態、線程組、SimpleDateFormat)

在這裏插入圖片描述

單例模式

立即加載(餓漢模式)

立即加載就是使用類的時候已經將對象創建完畢,常見的實現辦法就是聲明的時候直接new實例化。

// 加載類時候創建對象:靜態變量
public class A {
	private static A a = new A();	// 加載類時候就創建
	private A(){}
	public static A getInstance(){
		return a;
	}
}

// 加載類時候創建對象:靜態代碼塊
public class A {
	private static A a;
	static {
		a = new A();	// 加載類時候就創建
	}
	private A(){}
	public static A getInstance(){
		return a;
	}
}

// 靜態內置類實現
public class A() {
	private static class AHandler {
		private static A a = new A();	// 加載類時候就創建
	}
	private A(){}
	public static A getInstance(){
		return AHandler.a;
	}
}

// 利用枚舉類的構造方法,枚舉類構造方法會在加載時候被自動調用
public class A() {
// 這麼封裝是爲了避免AEnum沒有特別作用,他只是封裝A內部作爲單例的實現
	private enum AEnum {
		bFactory;
		
		private B b;
		private A() {
			b = new B();
		}
		public static B getB() {
			return b;
		}
	}
	public static B getB() {
		return AEnum.bFactory.getB();
	}
}

延遲加載(懶漢模式)

延遲加載就是在要首次使用類的時候才進行對象的創建,常見的實現辦法就是在get()或者getInstance()方法中進行new實例化。

public class A {
	private static ObjectA a;
	private A(){}
	public static A getInstance(){
		if (a == null) {
			a = new A();
		}
		return a;
	}
}

延遲加載的同步問題

延遲加載由於可能出現多個線程同時進入a = new A();的代碼塊,所以a可能被多次創建,就不符合單例模式的設計,那麼可以通過以下幾個方法進行解決:
同步方法
給獲取實例的方法加鎖,所有進入方法的線程都要排隊進入。但是這種方式效率比較低下,一次只能由一個對象進入,即使在初始化完對象之後。

public synchronized static A getInstance(){}

同步代碼塊
效果等於同步方法

public static A getInstance(){
	synchronized(A.class) {
		if (a == null) {
			a = new A();
		}
		return a;
	}
}

DCL雙檢查鎖機制
這種方式解決了當a初始化完成之後,還需要不斷進入同步代碼塊的情況,當a初始化完成之後,就直接返回對象,不會進入同步塊,同時呢,保證a在初始化過程中,進入同步代碼塊會再判斷一次,避免多個線程同時通過第一層判空的情況。

public static A getInstance(){
	if (a == null) {
		synchronized(A.class) {
			if (a == null) {
				a = new A();
			}
		}
	}
	return a;
}

線程狀態

  • NEW 至今尚未啓動的線程,線程剛剛創建完;
  • RUNNABLE 正在JVM中執行的線程,(包含就緒態和執行態,與其他線程輪流使用CPU時間);
  • BLOCKED 被阻塞並等待某個鎖,等待synchronized或者Lock
  • WAITING 調用了wait()方法,等待喚醒,一般是調用了wait()join()方法,等待喚醒或子線程執行完成;
  • TIMED_WAITING 有限時間內等待其他線程的喚醒,一般是調用了wait(long)join(long)sleep(long)等等待時間段過去,自動喚醒的線程狀態;
  • IERMINATED 已退出,執行完成,已經退出的線程狀態。

線程組

可以將線程歸屬到某一個線程組中,批量的管理線程或者線程組對象,有效的進行組織。線程組中可以包含線程或者線程組。
線程組
使用方法

public class Run {
	public static void main(String[] args) {
		ThreadA a = new ThreadA();
		ThreadB b = new ThreadB();
		ThreadGroup group = new ThreadGroup("threadGroupA");
		
		Thread aThread = new Thread(group, a);
		Thread bThread = new Thread(group, b);
		group.start();	// 批量啓動
		// group.interrupt();	// 批量終止
	}
}

SimpleDateFormat在多線程條件下不安全

多線程環境中使用SimpleDateFormat比較容易出現時間混亂的情況。
一般有下幾種解決方式:

  1. 每個時間的解析都new一個新的SimpleDateFormat對象,確保線程之間不共享SimpleDateFormat對象;
  2. 採用ThreadLocal類,確保一個SimpleDateFormat對象只在同一時間被一個線程所使用;

線程的異常處理

處理可以通過set異常處理器來解決,優先級別爲:

  1. Thread對象的setUncaughtExceptionHandler()方法;
  2. Thread類的setDefaultUncaughtExceptionHandler()方法;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章