单例模式定义:确保一个类只有一个实例,并提供一个全局访问点。全局访问点的概念有点类似于java中的全局变量的概念,但是单例模式的方式比全局变量效率更高,因为全局访问点在程序开始到结束都要占用资源,但是单例模式则是在用到时才占用资源。下面实现一个单例模式Demo。
单例模式类
package test;
public class Singleton {
public static int a = 0;
public int tag = 0;
private static Singleton uniqueInstance;// 将变量设为私有,防止外部引用
// 私有的默认构造函数,防止使用构造函数进行实例化
private Singleton() {
this.tag = ++a;// 实例化一次Singleton类,则tag自加1
// for循环作用是等待
for (int i = 0; i < 100000; i++) {
}
}
/**
* 对getInstance()方法进行锁定,synchronized同步防止多线程环境同时执行,这种方式偶尔会导致Singleton被多次实例化
*
* @return
*/
// public synchronized static Singleton getInstance() {
// if (uniqueInstance == null) {
// uniqueInstance = new Singleton();
// }
// return uniqueInstance;
// }
/**
* synchronized对语句块进行锁定,而不是对方法锁定
*
* @return
*/
public static Singleton getInstance() {
if (uniqueInstance == null) {
// synchronized同步的必须是类:Singleton.class,而不能是类的对象:uniqueInstance
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
测试类
package test;
public class Test {
public static void main(String[] args) {
// 主线程启动第一个子线程
new Thread() {
public void run() {
for (int i = 0; i < 1000; i++) {
new TestThread(i).start();
}
}
}.start();
// 主线程启动第二个子线程,与此同时第一个子线程还没有结束,这样,此时的状态就是一个主线程,两个子线程,并且两个子线程都想实例化Singleton对象
new Thread() {
public void run() {
for (int i = 1000; i < 2000; i++) {
new TestThread(i).start();
}
}
}.start();
}
/**
* 定义测试线程内部类,线程先休眠随机时间,然后调用Singleton.getInstance()实例化一个Singleton对象
*
* @author CYL
*
*/
public static class TestThread extends Thread {
private int i;
public TestThread(int i) {
this.i = i;
}
@Override
public void run() {
try {
Thread.sleep((long) (Math.random() * 10));
} catch (InterruptedException e) {
e.printStackTrace();
}
Singleton s = Singleton.getInstance();
if (s.tag != 1)
System.out.println(i + "\t" + s.tag);
super.run();
}
}
}
测试结果:无打印输出,如果是Singleton被实例化了多个对象,则会打印出实例化次数。