概述
无论是synchronized关键字还是显氏锁Lock,都会牺牲系统的性能。不可变对象一定是线程安全的。
定义不可变类
package com.Reyco.MyThread;
public final class Person {
private final String name;
private final String address;
public String getName() {
return name;
}
public String getAddress() {
return address;
}
public Person(String name, String address) {
super();
this.name = name;
this.address = address;
}
@Override
public String toString() {
return "Person [name=" + name + ", address=" + address + "]";
}
}
不可变类的设计方法
- 类添加final修饰符,防止类被继承
- 保证所有成员必须私有,并且加上final修饰
- 不提供改变成员变量的方法,包括setter
- 通过构造器初始化所有成员,进行深拷贝
private final byte[] mybuffer;
public Person(byte[] buffer) {
this.mybuffer=buffer;
}
这种方式不能保证不可变行,mybuffer和buffer指向同一块内存地址,用户可以在Person之外修改buffer进而修改mybuffer。
为了保证值不被改变,需要对引用类型进行深拷贝
private final byte[] mybuffer;
public Person(byte[] buffer) {
this.mybuffer=buffer。clone();
}
5.在getter方法中,不要返回对象本身,返回对象的拷贝
操作不可变的线程是线程安全的
public class PersonThread extends Thread{
private Person person;
public PersonThread(Person person) {
this.person=person;
}
@Override
public void run() {
System.out.println(person.toString());
}
}
String是否真的不可变
大家都知道String类是不可变类,但是我们可以尝试下采用反射的方式来改变String对象。
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
String name="Reyco";
//获取String类的value字段
Field valueField=String.class.getDeclaredField("value");
//改变value属性的访问权限
valueField.setAccessible(true);
//获取name对象上的属性值
char[] value = (char[])valueField.get(name);
value[2]='b';
System.out.println(name);
}