多线程不可变对象设计模式immutable
Posted zheaven
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程不可变对象设计模式immutable相关的知识,希望对你有一定的参考价值。
immutable特点:
1.不可变对象一定是线程安全的(里面的任何属性或者引用类型的属性一旦被初始化,都不能被修改)
2.可变对象不一定是不安全的 StringBuffer
题外话:
J2EE中
servlet 全局只创建一个对象,不是线程安全的
struts 1.x Action也不是线程安全的,只创建一个Action实例
struts 2.x Action是线程安全的,会为每一个请求创建一个Action实例
一个不可变对象类
package com.dwz.concurrency2.chapter8; public final class Person { private final String name; private final String address; public Person(String name, String address) { super(); this.name = name; this.address = address; } public String getName() { return name; } public String getAddress() { return address; } @Override public String toString() { return "Person [name=" + name + ", address=" + address + "]"; } }
使用不可变对象的线程类
package com.dwz.concurrency2.chapter8; public class UsePersonThread extends Thread { private Person person; public UsePersonThread(Person person) { this.person = person; } @Override public void run() { while (true) { System.out.println(Thread.currentThread().getName() + " print " + person.toString()); } } }
测试
package com.dwz.concurrency2.chapter8; import java.util.stream.IntStream; public class ImmutableClient { public static void main(String[] args) { //share data Person person = new Person("Alex", "shanxi"); IntStream.range(0, 5).forEach(i -> new UsePersonThread(person).start() ); } }
不可变对象中对list引用的处理
package com.dwz.concurrency2.chapter8; import java.util.ArrayList; import java.util.Collections; import java.util.List; public final class ImmutableTest { private final int age; private final String name; private final List<String> list; public ImmutableTest(int age, String name) { this.age = age; this.name = name; this.list = new ArrayList<>(); } public int getAge() { return age; } public String getName() { return name; } public List<String> getList() { return Collections.unmodifiableList(list); } }
举例说明在实现线程安全方面,不可变对象和synchronized的性能差异
package com.dwz.concurrency2.chapter8; public class ImmutablePerformance { public static void main(String[] args) throws InterruptedException { long startTimeStamp = System.currentTimeMillis(); //SyncObj 3742 单线程 SyncObj syncobj = new SyncObj(); syncobj.setName("Alex"); for(long i = 0L; i < 1000000; i++) { System.out.println(syncobj.toString()); } //ImmutableObj 3365 单线程 ImmutableObj ImmutableObj = new ImmutableObj("dandan"); for(long i = 0L; i < 1000000; i++) { System.out.println(ImmutableObj.toString()); } //SyncObj 10009 多线程 16963 //ImmutableObj 9452 多线程 16750 Thread t1 = new Thread() { @Override public void run() { for(long i = 0L; i < 3000000; i++) { System.out.println(Thread.currentThread().getName() + "=" + ImmutableObj.toString()); } } }; Thread t2 = new Thread() { @Override public void run() { for(long i = 0L; i < 1000000; i++) { System.out.println(Thread.currentThread().getName() + "=" + ImmutableObj.toString()); } } }; t1.start(); t2.start(); t1.join(); t2.join(); long endTimeStamp = System.currentTimeMillis(); System.out.println("Elapsed time " + (endTimeStamp - startTimeStamp)); } } final class ImmutableObj { private final String name; public ImmutableObj(String name) { this.name = name; } @Override public String toString() { return "[" + name + "]"; } } class SyncObj { private String name; public synchronized void setName(String name) { this.name = name; } @Override public synchronized String toString() { return "[" + name + "]"; } }
结果表明:不可变对象确实比synchronized性能有所提升
那么在实现自定义的Immutable的Class的时候,应该注意哪些要点呢?
a)Class 应该定义成final,避免被继承。
b)所有的成员变量应该被定义成final。
c)不要提供可以改变类状态(成员变量)的方法。【get 方法不要把类里的成员变量让外部客服端引用,当需要访问成员变量时,返回成员变量的copy】
d)构造函数不要引用外部可变对象。如果需要引用外部可以变量,应该在构造函数里进行defensive copy。
以上是关于多线程不可变对象设计模式immutable的主要内容,如果未能解决你的问题,请参考以下文章
多线程----Immutable VS Mutable (可变与不可变)