1、饿汉式:在程序启动或者类单件加载的过程中,类得实例已经创建,在多线程高并发情况下是线程安全的
示例:
/**
* 饿汉式单例
*/
class ClassB {
/**
* static关键字,会在类加载的过程中最先初始化
*/
private static ClassB instance = new ClassB();
private ClassB() {
}
public static ClassB getInstance() {
return instance;
}
}
2、懒汉式:类对外提供获取实例的方法,外部第一次访问程序时才会创建
下面这种懒汉式存在线程不安全的问题:
/**
* 懒汉式单例
*/
public class ClassA {
private static ClassA instance;
private ClassA() {
}
public static ClassA getInstance() {
if(null == instance) {
instance = new ClassA();
}
return instance;
}
}
新建一个线程获取ClassA的实例:
public class MyThread extends Thread{
@Override
public void run() {
System.out.println(ClassA.getInstance().hashCode());
}
}
测试:
public class TestClassA {
public static void main(String arg[]) {
List list = new ArrayList<MyThread>();
for (int i = 0; i < 10; i++) {
MyThread thread = new MyThread();
list.add(thread);
}
for (int i = 0; i < 10; i++) {
MyThread thd = (MyThread)list.get(i);
thd.start();
}
}
}
输出结果:
1141021789
475341210
798732982
798732982
723260323
876349272
1141021789
1721087309
510633378
1721087309
3、如何创建一个线程安全的懒汉式单例:
/**
* 懒汉式单例,线程安全
*/
public class ClassA {
/**
* 1、可见性定义:线程和线程之前,一个线程修改结果对另一个线程是可见的
* 即一个线程修改后另一个线程立即能看到
* 2、具有可见性的关键字有volatile、final、synchronized
* 3、volatile修饰的关键字,不允许线程内部进行缓存和重排序的,
* 即线程和线程之间是可见的
*/
volatile private static ClassA instance;
private ClassA() {
}
public static ClassA getInstance() {
try {
if(instance != null) {
} else {
Thread.sleep(100);
synchronized(ClassA.class ) {
if (null == instance) {
instance = new ClassA();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
}
使用volatile关键字修改instance,初始化ClassA时使用synchronized关键字加锁,即 双检查加锁机制。