6基础知识笔记二

来源:互联网 发布:网络恢复mac系统 编辑:程序博客网 时间:2024/06/06 00:11

安全的对象构造过程

不要在构造过程使用this引用逸出。

可以使用工厂方法来防止this引用在构造过程中逸出。

public class SafeListener{private final EventListener listener;private SafeListener(){listener = new EventListener(){public void onEvent(Event e){doSomething(e);}};}public static SafeListener new Instance(EventSource source){SafeListener safe = new SafeListener();source.registerListener(safe.listener);return safe;}}
这里没有看明白为什么使用了私有的构造方法就能避免this引用逸出了?个人觉得这样照样可以在里面使用this引用,一时还没有想明白。

线程封闭

如果仅在单线程内访问数据,就不需要同步。这种技术被称为线程封闭,它是实现线程安全最简单的方式之一。

有三种线程封闭方式:Ad-线程封闭、栈封闭、ThreadLocal类。

Ad-线程封闭是指,维护线程封闭性的职责完全由程序实现了承担。

栈封闭式线程封闭的一种特例,在栈封闭中,只能通过局部变量才能访问对象。如果在线程内部上下文中使用非线程安全的对象,那么该对象仍然是线程安全的。

ThreadLocal类是维持线程封闭性的一种更规范方法。ThreadLocal提供了get与set等访问接口或方法,这些方法都为每个使用该变量的线程都存有一份独立的副本,因此get总是返回当前执行线程在调用set时设置的最新值。ThreadLocal对象通常用于防止对可变的单实例变量或全局变量进行共享。

private static ThreadLocal<Connection> connectionHolder= new ThreadLocal<Connection>(){public Connection initialValue(){return DriverManager.getConnection(DB_URL);}};public static Connection getConnection(){return connectionHolder.get();}


不变性

如果某个对象在被创建后其状态就不能被修改,那么这个对象就被称为不可变对象。不可变对象一定是线程安全的一个对象所有的域都声明为final类型的,这个对象也仍然是可变的,因为final类型的域可以保存可变对象的引用

当满足以下条件时,对象才是不可变的:

  1. 对象创建后其状态不能被修改。
  2. 对象所有域都是final类型的。
  3. 对象是正确创建的(在对象的创建期间,this引用没有逸出)。
如果类有任何可变对象引用,那么当它们在类和类的调用者间传递的时候必须保护性拷贝。

Final域
final类型的引用变量指向的引用对象,是不能重新指向其它的引用对象。final域能确保初始化过程的安全性,从而不受限制被访问,在共享对象时无须同步。

安全发布
对象安全地发布:
  • 在静态初始化函数中初始化一个对象引用。
  • 将对象的引用保存到volatile类型的域或者AtomicReferance对象中。
  • 将对象的引用保存操某个正确构造对象的final类型域中。
  • 将对象的引用保存到一个由锁保护的域中。
事实不可变对象
如果对象从技术上来看是可变的,但其状态在发布后不会再改变,那么把这种对象称为“事实不可变对象”。
在没有额外的同步的情况下,任何线程都可以使用被安全发布地事实不可变对象。

对象的发布需求取决于它的可变性:
  • 不可变对象可以通过任意机制来发布。
  • 事实不可变对象必须通过安全机制来发布。
  • 可变对象必须通过安全机制来发布,并且是线程安全的或者由某个锁保护起来。
在并发程序中使用和共享对象时,可以使用一些实用的策略,包括:

线程封闭。

只读共享。

线程安全共享。线程安全的对象内部实现同步。

保护对象。线程通过获得锁来访问。