/**
* 读取应用配置文件
*/
public class AppConfig {
/**
* 用来存放配置文件中参数A的值
*/
private String parameterA;
/**
* 用来存放配置文件中参数B的值
*/
private String parameterB;
return parameterA;
}
public String getParameterB() {
return parameterB;
}
/**
* 构造方法
*/
public AppConfig(){
//调用读取配置文件的方法
readConfig();
}
/**
* 读取配置文件,把配置文件中的内容读出来设置到属性上
*/
private void readConfig(){
Properties p = new Properties();
InputStream in = null;
try {
in = AppConfig.class.getResourceAsStream(
"AppConfig.properties");
p.load(in);
//把配置文件中的内容读出来设置到属性上
this.parameterA = p.getProperty("paramA");
this.parameterB = p.getProperty("paramB");
} catch (IOException e) {
System.out.println("装载配置文件出错了,具体堆栈信息如下:");
e.printStackTrace();
}finally{
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|
paramA=a
paramB=b
|
public class Client {
public static void main(String[] args) {
//创建读取应用配置的对象
AppConfig config = new AppConfig();
String paramA = config.getParameterA();
String paramB = config.getParameterB();
System.out.println("paramA="+paramA+",paramB="+paramB);
}
}
|
paramA=a,paramB=b
|
保证一个类仅有一个实例,并提供一个访问它的全局访问点。 |
/**
* 懒汉式单例实现的示例
*/
public class Singleton {
/**
* 定义一个变量来存储创建好的类实例
*/
private static Singleton uniqueInstance = null;
/**
* 私有化构造方法,可以在内部控制创建实例的数目
*/
private Singleton(){
//
}
/**
* 定义一个方法来为客户端提供类实例
* @return 一个Singleton的实例
*/
public static synchronized Singleton getInstance(){
//判断存储实例的变量是否有值
if(uniqueInstance == null){
//如果没有,就创建一个类实例,并把值赋值给存储类实例的变量
uniqueInstance = new Singleton();
}
//如果有值,那就直接使用
return uniqueInstance;
}
/**
* 示意方法,单例可以有自己的操作
*/
public void singletonOperation(){
//功能处理
}
/**
* 示意属性,单例可以有自己的属性
*/
private String singletonData;
/**
* 示意方法,让外部通过这些方法来访问属性的值
* @return 属性的值
*/
public String getSingletonData(){
return singletonData;
}
}
|
/**
* 饿汉式单例实现的示例
*/
public class Singleton {
/**
* 定义一个变量来存储创建好的类实例,直接在这里创建类实例,只能创建一次
*/
private static Singleton uniqueInstance = new Singleton();
/**
* 私有化构造方法,可以在内部控制创建实例的数目
*/
private Singleton(){
//
}
/**
* 定义一个方法来为客户端提供类实例
* @return 一个Singleton的实例
*/
public static Singleton getInstance(){
//直接使用已经创建好的实例
return uniqueInstance;
}
/**
* 示意方法,单例可以有自己的操作
*/
public void singletonOperation(){
//功能处理
}
/**
* 示意属性,单例可以有自己的属性
*/
private String singletonData;
/**
* 示意方法,让外部通过这些方法来访问属性的值
* @return 属性的值
*/
public String getSingletonData(){
return singletonData;
}
}
|
/**
* 读取应用配置文件,单例实现
*/
public class AppConfig {
/**
* 定义一个变量来存储创建好的类实例,直接在这里创建类实例,只能创建一次
*/
private static AppConfig instance = new AppConfig();
/**
* 定义一个方法来为客户端提供AppConfig类的实例
* @return 一个AppConfig的实例
*/
public static AppConfig getInstance(){
return instance;
}
/**
* 用来存放配置文件中参数A的值
*/
private String parameterA;
/**
* 用来存放配置文件中参数B的值
*/
private String parameterB;
public String getParameterA() {
return parameterA;
}
public String getParameterB() {
return parameterB;
}
/**
* 私有化构造方法
*/
private AppConfig(){
//调用读取配置文件的方法
readConfig();
}
/**
* 读取配置文件,把配置文件中的内容读出来设置到属性上
*/
private void readConfig(){
Properties p = new Properties();
InputStream in = null;
try {
in = AppConfig.class.getResourceAsStream(
"AppConfig.properties");
p.load(in);
//把配置文件中的内容读出来设置到属性上
this.parameterA = p.getProperty("paramA");
this.parameterB = p.getProperty("paramB");
} catch (IOException e) {
System.out.println("装载配置文件出错了,具体堆栈信息如下:");
e.printStackTrace();
}finally{
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|
public class Client {
public static void main(String[] args) {
//创建读取应用配置的对象
AppConfig config = AppConfig.getInstance();
String paramA = config.getParameterA();
String paramB = config.getParameterB();
System.out.println("paramA="+paramA+",paramB="+paramB);
}
}
|
设计模式
|
注意 |
另外请注意一点,这里讨论的单例模式并不适用于集群环境,对于集群环境下的单例这里不去讨论,它不属于这里的内容范围。
|
private Singleton(){
}
|
public Singleton getInstance(){
}
|
public static Singleton getInstance(){
}
|
public static Singleton getInstance(){
return new Singleton();
}
|
private Singleton instance = null;
|
private static Singleton instance = null;
|
public static Singleton getInstance(){
//先判断instance是否有值
if(instance == null){
//如果没有值,说明还没有创建过实例,那就创建一个
//并把这个实例设置给instance
instance = new Singleton ();
}
//如果有值,或者是创建了值,那就直接使用
return instance;
}
|
public class Singleton {
//4:定义一个变量来存储创建好的类实例
//5:因为这个变量要在静态方法中使用,所以需要加上static修饰
private static Singleton instance = null;
//1:私有化构造方法,好在内部控制创建实例的数目
private Singleton(){
}
//2:定义一个方法来为客户端提供类实例
//3:这个方法需要定义成类方法,也就是要加static
public static Singleton getInstance(){
//6:判断存储实例的变量是否有值
if(instance == null){
//6.1:如果没有,就创建一个类实例,并把值赋给存储类实例的变量
instance = new Singleton();
}
//6.2:如果有值,那就直接使用
return instance;
}
}
|
//4:定义一个静态变量来存储创建好的类实例
//直接在这里创建类实例,只能创建一次
private static Singleton instance = new Singleton();
//1:私有化构造方法,可以在内部控制创建实例的数目
private Singleton(){
}
//2:定义一个方法来为客户端提供类实例
//3:这个方法需要定义成类方法,也就是要加static
public static Singleton getInstance(){
return instance;
}
}
|
注意一下,这个方案用到了static的特性,而第一个方案却没有用到,因此两个方案的步骤会有一些不同。在第一个方案里面,强制加上static也是算作一步的,而在这个方案里面,是主动加上static,就不能单独算作一步了。 |
提
示
|
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
|
public class Singleton {
private static Singleton instance = null;
}
public static Singleton getInstance(){
//判断存储实例的变量是否有值
if(instance == null){
//如果没有,就创建一个类实例,并把值赋给存储类实例的变量
}
//如果有值,那就直接使用
return instance;
}
}
|
/**
* Java中缓存的基本实现示例
*/
public class JavaCache {
/**
* 缓存数据的容器,定义成Map是方便访问,直接根据key就可以获取Value了
* key选用String是为了简单,方便演示
*/
private Map<String,Object> map = new HashMap<String,Object>();
/**
* 从缓存中获取值
* @param key 设置时候的key值
* @return key对应的Value值
*/
public Object getValue(String key){
//先从缓存里面取值
Object obj = map.get(key);
//判断缓存里面是否有值
if(obj == null){
//如果没有,那么就去获取相应的数据,比如读取数据库或者文件
//这里只是演示,所以直接写个假的值
obj = key+",value";
//把获取的值设置回到缓存里面
map.put(key, obj);
}
//如果有值了,就直接返回使用
return obj;
}
}
|
/**
* 使用缓存来模拟实现单例
*/
public class Singleton {
/**
* 定义一个默认的key值,用来标识在缓存中的存放
*/
private final static String DEFAULT_KEY = "One";
/**
* 缓存实例的容器
*/
private static Map<String,Singleton> map =
new HashMap<String,Singleton>();
/**
* 私有化构造方法
*/
private Singleton(){
//
}
public static Singleton getInstance(){
//先从缓存中获取
Singleton instance = (Singleton)map.get(DEFAULT_KEY);
//如果没有,就新建一个,然后设置回缓存中
if(instance==null){
instance = new Singleton();
map.put(DEFAULT_KEY, instance);
}
//如果有就直接使用
return instance;
}
}
|
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
|
public static Singleton getInstance(){
if(instance == null){
}
return instance;
}
|
时间 |
A线程
|
B线程
|
if(instance == null){
//判断结果为true,进入
|
public static Singleton getInstance(){
|
new Singleton();//创建实例中,但是还没有创建完成
|
if(instance == null){//判断结果也为true,也能进入,出问题了
|
把创建的实例赋值给instance,然后:return instance;
|
先instance = new Singleton();
然后:return instance;
|
public static synchronized Singleton getInstance(){}
|
注 意
|
在Java1.4及以前版本中,很多JVM对于volatile关键字的实现有问题,会导致双重检查加锁的失败,因此双重检查加锁的机制只能用在Java5及以上的版本。
|
public class Singleton {
/**
* 对保存实例的变量添加volatile的修饰
*/
private volatile static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance(){
//先检查实例是否存在,如果不存在才进入下面的同步块
if(instance == null){
//同步块,线程安全地创建实例
synchronized(Singleton.class){
//再次检查实例是否存在,如果不存在才真正地创建实例
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
|
提示 |
由于volatile关键字可能会屏蔽掉虚拟机中一些必要的代码优化,所以运行效率并不是很高。因此一般建议,没有特别的需要,不要使用。也就是说,虽然可以使用“双重检查加锁”机制来实现线程安全的单例,但并不建议大量采用,可以根据情况来选用。
|
public class Singleton {
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
* 没有绑定关系,而且只有被调用到时才会装载,从而实现了延迟加载
*/
private static class SingletonHolder{
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static Singleton instance = new Singleton();
}
/**
* 私有化构造方法
*/
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
|
/**
* 使用枚举来实现单例模式的示例
*/
public enum Singleton {
/**
* 定义一个枚举的元素,它就代表了Singleton的一个实例
*/
uniqueInstance;
/**
* 示意方法,单例可以有自己的操作
*/
public void singletonOperation(){
//功能处理
}
}
|
单例模式的本质:控制实例数目。 |
/**
* 简单演示如何扩展单例模式,控制实例数目为3个
*/
public class OneExtend {
/**
* 定义一个缺省的key值的前缀
*/
private final static String DEFAULT_PREKEY = "Cache";
/**
* 缓存实例的容器
*/
private static Map<String,OneExtend> map =
new HashMap<String,OneExtend>();
/**
* 用来记录当前正在使用第几个实例,到了控制的最大数目,就返回从1开始
*/
private static int num = 1;
/**
* 定义控制实例的最大数目
*/
private final static int NUM_MAX = 3;
private OneExtend(){}
String key = DEFAULT_PREKEY+num;
OneExtend oneExtend = map.get(key);
if(oneExtend==null){
oneExtend = new OneExtend();
map.put(key, oneExtend);
}
//把当前实例的序号加1
num++;
if(num > NUM_MAX){
//如果实例的序号已经达到最大数目了,那就重复从1开始获取
num = 1;
}
return oneExtend;
}
public static void main(String[] args) {
OneExtend t1 = getInstance ();
OneExtend t2 = getInstance ();
OneExtend t3 = getInstance ();
OneExtend t4 = getInstance ();
OneExtend t5 = getInstance ();
System.out.println("t1=="+t1);
System.out.println("t2=="+t2);
System.out.println("t3=="+t3);
System.out.println("t4=="+t4);
System.out.println("t5=="+t5);
System.out.println("t6=="+t6);
}
}
|
t1==cn.javass.dp.singleton.example9.OneExtend@6b97fd
t2==cn.javass.dp.singleton.example9.OneExtend@1c78e57
t3==cn.javass.dp.singleton.example9.OneExtend@5224ee
t4==cn.javass.dp.singleton.example9.OneExtend@6b97fd
t5==cn.javass.dp.singleton.example9.OneExtend@1c78e57
t6==cn.javass.dp.singleton.example9.OneExtend@5224ee
|
注意 |
这种实现方式同样是线程不安全的,需要处理,这里就不再展开去讲解了。
|