您的当前位置:首页正文

多线程设计模式之Immutable模式

2024-11-28 来源:个人技术集锦

一. Immutable模式

        Immutable就是不可变, 不发生改变的意思, Immutable模式中存在着确保实例状态不发生改变的类(Immutable类), 在访问这些实例时并不需要执行耗时的互斥处理, 因此如果能巧妙利用该模式, 可以提高程序的性能

二. 示例程序

2.1 类的一览表

类名说明
Person表示人的实体类
Main测试主程序
PrintPersonThread显示Person实例的线程类

2.2 使用Immutable模式的Person类

        代码中Person类用于表示人, 包含name和address两个字段

        Person类中的字段只能通过构造函数赋值, 类中有getter方法, 但是并没有setter方法, 因此Person类实例一旦创建, 其字段的值就不会发生改变

        这样即便有多个线程访问同一个实例, Person类也是安全的, Person类中的所有方法也都允许多个线程同时执行, Person类中的getter方法, 和toString()方法, 也无需声明为syncronized

        Person类声明为了final类型, 这表示无法创建Person类的子类, 虽然这不是Immutable模式的必要, 但是也能防止子类的继承而修改Person类中的字段的值

        Person类的字段name和address都设置为private, 也就是说, 这两个字段都只有从Person类中的内部才能访问, 这也不是Immutable模式的必要条件, 但也是防止子类修改字段值的一种措施, 另外, 这2个字段都声明为了final, 意味着一旦被复制, 就不会被修改

public class PrintPersonThread extends Thread {

    private Person person;

    public PrintPersonThread(Person person) {
        this.person = person;
    }

    @Override
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName() + "print" + person);
        }
    }

    static class Main {
        public static void main(String[] args) {
            Person person = new Person("alice", "Alaska");
            new PrintPersonThread(person).start();
            new PrintPersonThread(person).start();
            new PrintPersonThread(person).start();
        }
    }
}

@Getter
public final class Person {

    private final String name;

    private final String address;

    public Person(String name, String address) {
        this.name = name;
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

 运行结果可以看到, 多个线程再调用toString()方法时, 字段值并没有出现异常

三.  Immutable模式中登场的角色

        Immutable角色是一个类, 在这个角色中, 字段的值不可被修改, 也不存在修改字段值的方法, Immutable角色的实例被创建后, 状态将不可在被修改, 这样Immutable角色的方法, 就不用再声明为synchronized, Person正是Immutable角色

四. Immutable模式何时使用

        Immutable模式改在哪些情况下使用呢, 换言之, 开发人员应该在什么情况下考虑不可变呢?

4.1 实例化创建后, 状态不在发生变化时

        首先, 如前文所述, "实例化创建后, 状态不再发生改变" 是必要条件, 实例的状态是由字段的值决定的, 所以将字段声明为final, 且不提供setter方法, 是重点所在, 但是即使字段的值不可变的, 字段引用的实例也会发生改变, 比如把Person的字段类型从Strin改为Stringbuffer

4.2 实例是共享的, 且被频繁访问

        Immutable模式的有优点是 "不需要syncchronized进行保护", 那就意味着能够在不失去安全性的前提下, 提高性能, 当实例被多个线程共享, 且有可能被频繁访问时, Immutable模式的优点就会凹凸显出来 

五. 标椎库中用到的Immutable模式

        这里介绍一些java的标椎库中用到的Immutable模式

5.1 表示字符串的 java.lang.String 类

        该类在创建完实例之后, 字符串的内容不会再发生变化

5.2 表示大数字的 java.math.BigInteget 类

        java.math.BigInteget 和 java.math.BigDecimal 类都是Immutable类, BigInteget表示有精度的整数, BigDecimal表示所有精度的数, 这两个类在实例赋值之后就不会再发生变化

5.3 表示正则表达模式的 java.util.regex.pattern 类

        java.util.regex.pattern 是Immutable模式, Pattern表示正则表达式的模式, 但即使在处理模式匹配时, 值也不会发生变化

5.4 java.lang.Integet 类等

        基本类型的包装类, 都是Immutable模式, 在实例化后, 实例包装的值不会再发生变化

    

     

   

        

显示全文