>>比如我改变了哥哥的某个特性(比如统一一下两个人穿一样颜色的衣服),那么方法是先换一个人之后再换另一个人,还是招两个人给兄弟两个一起换那??如果是第一种方式,就需要同步时间(时间成本以及锁),第二种方式需要更多的资源(双线程,事务锁),同时如果是分布应用还需要网络传输。这些东西你从来不用考虑是么??
呵呵,这种情况下,兄弟俩穿一样颜色的衣服,这个状态就是不变量约束,而这种状态是有兄弟两个对象的状态共同组成的,所以我一般会将其封装,比如有一个名字叫"BrotherGroup"的对象,这个对象暴漏一个换衣服的方法,系统中所有的换衣服的操作,必须通过BrotherGroup的changeCloths()方法,而不是将兄弟两个随便暴漏给其他对象,让其随便换衣服,这样这个方法要保证兄弟两个的衣服一颜色在执行完这个方法后是一样的,而衣服颜色一样不仅是BrotherGroup对象的不变量约束,同时也是changeCloths()方法的后验条件,这样我们就通过控制外层的对象的方法达到了控制内部封装对象的状态,此时即使兄弟两个对象各自换衣服的方法不是线程安全的,只要我们保证BrotherGroup的changeCloths()方法是线程安全的就行了,这也是并发编程中的“实例限制”。
ps:多线程环境下的状态控制可以分为两种,一种是共享变量的控制,另外一种就是不共享变量来控制,至于我们讨论的缓存采取的是共享变量的并发访问控制,此时需要通过锁{JAVA内部锁,私有的对象锁,共享的外部锁(当然共享的外部锁个不推荐使用,因为状态很难跟踪)}来保证对象状态的不变量。而另外一种不共享状态的并发访问我们也可以采用threadlocal,栈限制等技术来解决。所以此时我们讨论的缓存是一个全局的缓存,就是共享的,所以通常只能通过锁的机制来保证状态的合法性。
所以我一直都说面向对象的设计对并发控制很重要,封装的越好,状态越容易控制,暴漏的越多,对象的安全发布就成为了大的问题。所以要想容易控制并发访问时对象的状态,请设计封装良好的对象模型,这样当我们系统中用了封装良好的对象模型后,自然而然的我会想到用缓存。对于那些丑陋的,没有经过封装以及不变量约束,方法后验条件保证的模型,即使你用了缓存,也是自找苦吃呵呵。