场景
immutable的意思是“不可变”
设计一个类,实例的内部状态不会发生变更,不用使用锁机制,线程安全。
代码实现
下面我设计一个Person的类,表示人
<code>public final class Person {
private final String sex;
private final String id;
private final String name;
public Person(String sex, String id, String name) {
this.name = name;
this.id = id;
this.sex = sex;
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public String getId() {
return id;
}
@Override
public String toString() {
return "Person{" +
"sex='" + sex + '\\'' +
", id='" + id + '\\'' +
", name='" + name + '\\'' +
'}';
}
}/<code>
说明:
1、属性只能在构造函数中赋值,没有setter方法,只有getter方法;
2、字段都是private final,意味着只能赋值一次,且只能在内部访问
3、类是final,表示无法创建子类,防止子类修改
下面我们来测试一下该类是否是线程安全的
实现显示Person信息的类
<code>
public class ShowPersonThread extends Thread {
private Person person;
public ShowPersonThread(Person person) {
this.person = person;
}
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + "——" + person);
}
}
}/<code>
实现主函数类
<code>
public class Main {
public static void main(String[] args) {
Person alice = new Person("女", "1222323", "lucy");
new ShowPersonThread(alice).start();
new ShowPersonThread(alice).start();
new ShowPersonThread(alice).start();
}
}/<code>
模式解读
什么时候使用?
1、实例在创建后,状态不会发生变化
比如上面的Person类,一旦创建,字段不会发生变化,不发生变化需要结合具体业务涉及,对于人而言,sex/id不会发生变化,一出生就决定了,name发生变化得几率很小
注意引用字段,引用字段的值不会变,但是其指向的值发生了变化
2、实例被共享
多个线程同时访问
由于没有使用锁,因此性能会比较高,对于那种需要频繁访问且很少变化的数据,能提高性能
String & StringBuffer
String
<code>
private final char value[];/<code>
注意字段是private final,无法变更
StringBuffer
<code>
AbstractStringBuilder
char[] value; /<code>
String是线程安全的,StringBuffer是线程不安全
final
1、修饰类,表示无法创建子类,子类无法重写其方法
2、修饰非静态方法,表示无法被子类重写;修饰静态方法,表示不会被子类隐藏
3、修饰字段
表示只能赋值一次
初始化方法:
比如:private final age= 1;
(2)构造函数中赋初值
对于静态final字段,初始化方法:
比如:private static final age= 2;
(2)静态代码块赋初值
private static final age;
static {
age = 12;
}
4、局部变量和函数参数
局部变量只能赋初值一次
函数参数不能再赋值,因为在调用的时候已经赋值一次,不能再赋值
ArrayList
ArrayList是可变大小的“数组“,是非线程安全的,下面用代码证实这一点
写线程类
<code>
import java.util.List;
public class WriteThread extends Thread{
private final List<string> list;
public WriteThread(List<string> list) {
super("写线程");
this.list = list;
}
public void run() {
int i = 0;
while(true) {
list.add(String.valueOf(i));
list.remove(0);
i++;
}
}
}/<string>/<string>/<code>
读线程类
<code>
import java.util.List;
public class ReadThread extends Thread{
private final List<string> list;
public ReadThread(List<string> list) {
super("读线程");
this.list = list;
}
public void run() {
while (true) {
for (String str : list) {
System.out.println(str);
}
}
}
}/<string>/<string>/<code>
主函数类
<code>
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<string> list = new ArrayList<string>();
new WriteThread(list).start();
new ReadThread(list).start();
}
}/<string>/<string>/<code>
执行程序,结果如下:
<code>
Exception in thread "ReaderThread" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at com.vedda.immutable.collection.sample1.ReadThread.run(ReadThread.java:16)/<code>
解决线程安全方法
使用Collections.synchronizedList
修改主函数如下:
<code>
public class Main {
public static void main(String[] args) {
final List<integer> list = Collections.synchronizedList(new ArrayList<integer>());
new WriterThread(list).start();
new ReaderThread(list).start();
}
}/<integer>/<integer>/<code>
读线程类run 方法修改如下:
<code>
public void run() {
while (true) {
synchronized (list) {
for (String str : list) {
System.out.println(str);
}
}
}
}/<code>
输出结果如下:
<code>2
1891942
1891942/<code>
运行正常,但是输出结果不是连续的,因为在读的时候,可以写线程已经写入多个值了
2、使用CopyOnWriteArrayList
修改主函数如下:
<code>public class Main {
public static void main(String[] args) {
final List<integer> list = new CopyOnWriteArrayList<integer>();
new WriterThread(list).start();
new ReaderThread(list).start();
}
}/<integer>/<integer>/<code>
修改读线程run方法:
<code>public void run() {
while (true) {
for (String str : list) {
System.out.println(str);
}
}
}/<code>
正常运行,输出结果如下:
<code>0
16
18
18/<code>
CopyOnWriteArrayList每次写操作时,都会复制集合,因此它比较适合读多写少场景。
閱讀更多 韋陀學院 的文章