第二章:创建和销毁对象:1、用静态工厂方法代替构造器

2019-07-10  本文已影响0人  莫夏_b560
类的成员分为两类,静态成员(static member)和实例成员(instance member)。静态成员属于类,实例成员则属于对象,即类的实例。

    简单讨论一下在一个类中使用静态字段(static field)和静态方法(static method)是否会有线程安全问题。 

    我们在知道, 静态字段(static field)和静态方法(static method)的调用是通过类来调用。静态方法不对特定的实例操作,只能访问静态成员。实例方法可对特定的实例操作,既能访问静态成员,也能访问实例成员。

    那么,在多线程中使用静态方法是否有线程安全问题?这要看静态方法是是引起线程安全问题要看在静态方法中是否使用了静态成员。

    因为,在多线程中使用同一个静态方法时,每个线程使用各自的实例字段(instance field)的副本,而共享一个静态字段(static field)。所以说,如果该静态方法不去操作一个静态成员,只在方法内部使用实例字段(instance field),不会引起安全性问题。但是,如果该静态方法操作了一个静态字段,则需要静态方法中采用互斥访问的方式进行安全处理。
    
    举个简单的例子,我们使用的Console.WriteLine();中WriteLine()是Console.WriteLine类的静态方法。

     对于ASP.NET, 多个客户端访问服务器端, 这是一个多线程的例子.只要理解了原因,我们可以在三层架构中的数据访问层中放心使用静态方法(static method)来访问数据库.

先看一个类:
public class Test
{
   public static String hello(String str)
   {
       String tmp = "";
       tmp = tmp + str;
       return tmp;
   }
}
hello方法会不会有多线程安全问题呢?没有!
静态方法如果没有使用静态变量,则没有线程安全问题。
为什么呢?因为静态方法内声明的变量,每个线程调用时,都会新创建一份,而不会共用一个存储单元。比如这里的tmp,每个线程都会创建自己的一份,因此不会有线程安全问题。
注意:静态变量,由于是在类加载时占用一个存储区,每个线程都是共用这个存储区的,所以如果在静态方法里使用了静态变量,这就会有线程安全问题
在多线程的环境下,如果每个线程需要单独的实例时,使用静态方法会不会导致数据混乱,因为每次的调用都返回同样的对象。

     在Spring的环境中Spring的组件(Bean)默认单例,找这么看是适合使用静态工厂方法的,而且Spring在处理并发时采用ThreadLocal来处理线程同步问题,它的方式是为每个独立的线程提供变量副本,当变量改变时只修改各自的副本,保证安全.所以在Spring中也适合使用静态工厂方法.

以Java中自带的Boolean类(基本类型boolean的包装类)为例,它的静态工厂方法为:

public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}


我们应该考虑用该方法替代构造器来获得一个Boolean的实例。

//使用构造器
Boolean b1 = new Boolean(true);
//使用静态工厂方法
Boolean b2 = Boolean.valueOf(true);


同样是传入一个true作为参数,两种方法有什么区别呢?
静态工厂方法的优点
优点1:它们有名称
假如我们想要提供多个具有相同签名的构造器,这在Java中是做不到的,除非把参数列表的顺序做些调整,但这会对用户很不友好。因此可以使用静态工厂方法,取不同的名字以表示不同的构造方式。
优点2:不必每次都创建新对象
适用于单例模式。
优点3:构成基于接口的框架
静态工厂方法返回对象所属的类可以是后来动态添加的。我们以服务提供者框架(Service Provider Framework)为例讲解,该框架的代表是JDBC API。
优点4:创建泛型类实例的代码更为简洁
请看下面两种创建泛型类实例的方式,后者比前者更为简洁。

//使用构造器创建
Map<String, List<String>> m1 = new HashMap<String, List<String>>();
//使用静态工厂方法创建
Map<String, List<String>> m2 = HashMap.newInstance();


前提是HashMap提供的静态工厂方法newInstance定义如下

public static <K, V> HashMap<K, V> newInstance() {
return new HashMap<K, V>();
}

上一篇下一篇

猜你喜欢

热点阅读