【多线程】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()方法;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章