`
su1216
  • 浏览: 670484 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Group-logo
深入入门正则表达式(jav...
浏览量:71877
E60283d7-4822-3dfb-9de4-f2377e30189c
android手机的安全问...
浏览量:128684
社区版块
存档分类
最新评论

多线程学习系列 - 2 - Immutable Pattern

阅读更多

目录

多线程学习系列 - 1 - Single Threaded Execution Pattern

多线程学习系列 - 2 - Immutable Pattern

 

先看看什么算是Immutable

immutable [i'mju:təbl](21世纪大英汉词典) adj.永远不变的;不可改变的;永恒的;无变化的

能够保证实例状态绝对不会改变的类,我们认为是immutable的

最常用的String就是immutable类

 

考虑下面Person类,看它是如何成为一个immutable类

它有属性String name和String address

public final class Person {
	private final String name;
	private final String address;
	public Person(String name, String address){
		this.name = name;
		this.address = address;
	}
	
	public String getName(){
		return name;
	}
	
	public String getAddress(){
		return address;
	}
	
	public String toString(){
		return "Person [name:" + name + "\t address:" + address + "]";
	}
}

类很简单,只有两个字段几个方法

首先Person非常凶猛,上场先挥刀自宫,把自己声明成final绝后,所以也就没有子类能修改父类属性的可能

然后把两个属性都声明为private,也就是说对外不可见,并且设置为final也禁止了set方法的再次赋值

至此Person功德圆满,成为了immutable类

 

ps:如果你使用反射,很遗憾,反射可以改变name和address的值,这里我们不考虑恶意改变,所以去除这种情况

测试代码如下

public static void main(String[] args) {
	Person p = new Person("Alice", "Alaska");
	System.out.println(p);;
	Class<Person> clazz = Person.class;
	try {
		Field feild = clazz.getDeclaredField("name");
		feild.setAccessible(true);
		feild.set(p, "Bobby");
		System.out.println(p);
	} catch (SecurityException e) {
		e.printStackTrace();
	} catch (NoSuchFieldException e) {
		e.printStackTrace();
	} catch (IllegalArgumentException e) {
		e.printStackTrace();
	} catch (IllegalAccessException e) {
		e.printStackTrace();
	}
}

打印结果

Person [name:Alice     address:Alaska]
Person [name:Bobby     address:Alaska]

 

Immutable Pattern的参与者

一个字段值无法更改的类,也没有任何用来更改字段值的方法。当Immutable参与者的实例建立后,状态就完全不再变化

 

Immutable Pattern适用性

1.当实例产生后,状态不需要再改变时(原文为状态不再变化时,我觉得改成不需要再改变时会更好)

其实只将字段定义为private final并且没有set方法,也还是有可能是mutable类的,后面会给出例子,上面的Person确实是immutable的

2.实例需要共享,而且访问很频繁时

使用immutable类可以省去synchronized,性能会节省不少且不丧失安全性

 

标准类链接库里使用到的Immutable Pattern

下面只简单列举一些

java.lang.String

java.awt.Color

和基本类型的包装类

java.lang.Boolean

java.lang.Byte

java.lang.Character

java.lang.Double

java.lang.Float

java.lang.Integer

java.lang.Long

java.lang.Short

java.lang.Void

 

习题2.5

一个人设计的line,看看这个line是否为不可变类

public class Line {
    private final Point startPoint;
    private final Point endPoint;
    public Line(int startx, int starty, int endx, int endy) {
        this.startPoint = new Point(startx, starty);
        this.endPoint = new Point(endx, endy);
    }
    public Line(Point startPoint, Point endPoint) {
        this.startPoint = startPoint;
        this.endPoint = endPoint;
    }
    public int getStartX() { return startPoint.getX(); }
    public int getStartY() { return startPoint.getY(); }
    public int getEndX() { return endPoint.getX(); }
    public int getEndY() { return endPoint.getY(); }
    public String toString() {
        return "[ Line: " + startPoint + "-" + endPoint + " ]";
    }
}

 

Point类

public class Point {
    public int x;
    public int y;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public int getX() { return x; }
    public int getY() { return y; }
    public String toString() {
        return "(" + x + "," + y + ")";
    }
}

 这里我们先不考虑继承的问题,因为人家设计完了,没有其余的类了

那么看看这个line,所有字段都为private final,方法都是get并且返回int和String

我们来看看这个构造函数

 

public Line(Point startPoint, Point endPoint) {
    this.startPoint = startPoint;
    this.endPoint = endPoint;
}

问题出在这个Point上

很容易看出,Point是可变的,line赋值之后Point改变了会怎样?很简单,line也被改变了

下面的代码证实了这点

public static void main(String[] args) {
	Point s = new Point(1, 2);
	Point e = new Point(3, 4);
	Line line = new Line(s, e);
	System.out.println(line);
	e.x = 5;
	System.out.println(line);
}

 打印结果

[ Line: (1,2)-(3,4) ]
[ Line: (1,2)-(5,4) ]

 

成对出现的mutable与immutable

如果有这样一个对象,它的一部分属性是不可变的另一部分是可变的,可以明显的区分出来,那么我们可以考虑将它拆分为两个类

一个为immutable另一个为mutable

比如String和StringBuffer

我们在java源码中可以看到

现在来看看下面两个成对出现的类,他们是否有安全问题

习题2.6

 

public final class ImmutablePerson {
    private final String name;
    private final String address;
    public ImmutablePerson(String name, String address) {
        this.name = name;
        this.address = address;
    }
    public ImmutablePerson(MutablePerson person) {
        this.name = person.getName();
        this.address = person.getAddress();
    }
    public MutablePerson getMutablePerson() {
        return new MutablePerson(this);
    }
    public String getName() {
        return name;
    }
    public String getAddress() {
        return address;
    }
    public String toString() {
        return "[ ImmutablePerson: " + name + ", " + address + " ]";
    }
}

 

public final class MutablePerson {
    private String name;
    private String address;
    public MutablePerson(String name, String address) {
        this.name = name;
        this.address = address;
    }
    public MutablePerson(ImmutablePerson person) {
        this.name = person.getName();
        this.address = person.getAddress();
    }
    public synchronized void setPerson(String newName, String newAddress) {
        name = newName;
        address = newAddress;
    }
    public synchronized ImmutablePerson getImmutablePerson() {
        return new ImmutablePerson(this);
    }
    String getName() {    // Called only by ImmutablePerson
        return name;
    }
    String getAddress() { // Called only by ImmutablePerson
        return address;
    }
    public synchronized String toString() {
        return "[ MutablePerson: " + name + ", " + address + " ]";
    }
}

  题目很简单,和2.5基本一样

public ImmutablePerson(MutablePerson person) {
    this.name = person.getName();
    this.address = person.getAddress();
}

 解释也和2.5一样,那么如何修改

在执行这个方法的时候,MutablePerson可能会改变,如何被改变,可以通过setPerson,setPerson使用了synchronized关键字,意为获得this的锁,那么我们只需也获取这个对象的锁,就可以保证setPerson和public ImmutablePerson(MutablePerson person)不会交叉执行了

代码如下

public ImmutablePerson(MutablePerson person) {
	synchronized (person) {
        this.name = person.getName();
        this.address = person.getAddress();
	}
}

这节内容较少,所以就不画图了

 

 

转贴请保留以下链接

本人blog地址

http://su1216.iteye.com/

http://blog.csdn.net/su1216/

分享到:
评论

相关推荐

    javabiginteger源码-MultiThreadMode:多线程模式

    优点:不需使用synchronized保护类的属性,适用于类被多个线程共享,且有可能被频繁访问。 标准类中mutable类:StringBuffer 标准类中Immutable类:String、BigInteger、BigDecimal、Pattern、基本类型的包装类 java...

    ikm_java_8.pdf

    在Java编程中,**多线程安全**是确保程序在多线程环境中能够正确运行的重要方面。下面是一些可以增加Java SE程序线程安全性的技术: - **b. 写类使它们不可变(Immutable)**:不可变对象是指一旦创建后就不能改变...

    JavaConcurrencyPattern:Java并发模式

    《Java多线程编程模式实战指南》系列文章配套源码。这些文章已扩充为一本书:《Java多线程编程实战指南(设计模式篇)》,由电子工业出版社出版,当当、亚马逊、京东、互动出版网、淘宝等各大书店有售。 【样章】 ...

    Google-guava 19.0

    Guava提供了原子类的扩展,如AtomicDoubleArray、AtomicLongMap等,以及Future和ListenableFuture,它们在多线程环境下提供了高效的同步机制。此外,CountDownLatch、CyclicBarrier、Semaphore等并发工具类也使得...

    Rust常见面试题.pdf

    - **并行性**:Rust内置了高级的并发模型,支持安全的多线程编程,有助于编写可扩展的应用程序。 - **跨平台**:Rust支持多种操作系统,如Windows、macOS和Linux等。 #### 2. Rust与C++相比有哪些优势和不同之处? ...

    Java String不可变性实现原理解析

    一、不可变模式(Immutable Pattern) 在并行软件开发过程中,同步操作似乎是必不可少的。当多线程对同一个对象进行读写操作时,为了保证对象数据的一致性和正确性,有必要对对象进行同步。而同步操作对系统性能是...

    通过实例解析java String不可变性

    一、不可变模式(Immutable Pattern) 在并行软件开发过程中,同步操作似乎是必不可少的。当多线程对同一个对象进行读写操作时,为了保证对象数据的一致性和正确性,有必要对对象进行同步。而同步操作对系统性能是...

    学习

    对于并发编程,Rust提供了一种名为“共享所有权”的模型,其中数据可以由多个线程同时读取,但写入操作必须互斥。这得益于其所有权和借用检查机制,Rust在编写线程安全的代码时无需依赖复杂的同步原语。 除此之外,...

    java常用的工具类

    8. **JUnit and TestNG**: 测试是软件开发中的重要环节,JUnit是Java单元测试的标准库,TestNG则提供了更丰富的功能,如支持多线程测试、参数化测试等。 9. **StringTokenizer 和 Pattern/Matcher**: `...

    guava23.0,用于安卓软件开发

    此外,它还包含了一些便捷的集合操作方法,如Joiner和Splitter用于字符串处理,以及Immutable集合类,确保集合在创建后无法被修改,这对于线程安全和防止意外修改非常有用。 2. **缓存机制**:Guava的Cache模块允许...

    effective-java:Intellij IDEA 的有效 Java 模式重构

    5. **接口的优先级高于抽象类(Prefer Interfaces to Abstract Classes)**:Java的多继承特性限制了抽象类的使用,接口则允许类实现多个行为。IntelliJ IDEA的"Extract Interface"功能可以帮助我们快速创建接口。 ...

    effective_java_new:Effective_java_new

    以上只是《Effective Java》中的一部分重要概念,实际书籍中还涉及了很多其他主题,包括集合、多线程、序列化、类设计等方面的最佳实践。通过对这些原则的深入理解和应用,Java开发者可以提升代码质量,编写出更专业...

    java英文对照表

    开关语句(Switch)根据表达式的值执行相应的代码块,同步(Synchronization)用于控制多线程的访问。语法(Syntax)是编程语言的规则,线程(Thread)是并发执行的程序部分。变量(Variable)存储数据,可见性...

Global site tag (gtag.js) - Google Analytics