java中地同步机制是使用关键字synchronized,它提供一种独占的加锁方式,还包括volatile变量,显式锁以及原子变量。
注意:
无状态的对象一定是线程安全的。
要保持状态的一致性,就需要在单个原子操作中更新所有相关的状态变量。
对于每个包含多个变量的不变形条件,其中涉及的所有变量度需要同一个锁来保护。
通常,在简单性与性能之间存在着相互制约的因素。当实现某个同步策略是一定不要盲目的为了性能牺牲简单性。
当执行时间轿车的计算或者可能无法快速完成的操作时,网络IO或者控制台IO,一定不要持有锁。
对象的共享:
在没有同步的情况下,编译器,处理器以及运行时等都可能对操作的执行顺序进行意向不到的调整,在缺乏足够的同步多线程程序中,要想对内存操作的执行顺序进行判断,几乎无法得到正确的结论。
加锁的含义不仅仅局限于互斥行为,还包括内存可见性,为了确保所有县城妒能看到共享变量的最新值,所有执行读操作和写操作的线程度必须在一个锁上同步。
把变量声明为volatile类型后,编译器于运行时都会注意到这个变量时共享的,因此不会讲该变量上的操作与其他内存操作仪器重排序,volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量总会返回罪行写入的值。
仅当volatile变量能简化代码的实现一机都同步策略验证时,才应该使用它们。如果在验证正确行使需要对可见性进行复杂的判断,那么就不要使用volatile变量。volatile变量的正确使用方式包括:确保它们自身状态的可见性,确保它们所引用对象的状态的可见性,一以及表示一些重要的程序生命周期时间的发生(例如初始化或者关闭)
加锁机制既可以保证可见性又可以保证原子性,而volatile变量只能确保可见性。
不要在构造过程中使用this引用逸出。
不可变对象一定是线程安全的。
满足一下条件是,对象才是不可变额:
对象创建以后其状态就不能修改
对象的所有与都是final类型
对象时正确创建的。(在创建期间,this引用没有逸出)
任务线程都可以再不需要额外同步的情况下安全地访问不可变对象,即使在发布这些对象时没有使用同步。
安全发布的常用模式:
要安全地发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确构造的对象可以通过以下方式来安全地发布:
在静态初始化函数中初始化一个对象引用。
将对象的引用保存到volatile类型的域或者AtomicReferance对象中。
将对象的引用保存到某个正确构造对象的final类型域中
将对象的引用保存到一个由锁保护的域中。
线程安全容器提供以下安全发布保证:
1 通过将一个键或者值放入Hashtable,synchronizedMap或者ConcurrentMap中可以安全地将它发布给任何从这些容器中访问它的线程。
2 通过将某个元素放入Vector,CopyOnWriteArrayList,CopyOnWriteArraySet,synchronizedList或者synchronizedSet中,可以讲该 元素安全地发布到任何从这些容器中访问该元素的线程。
3通过将某个元素放入BlockingQueue或者ConcurrentLinkedQueue中,可以讲钙元素安全地发布到任何从这些队列中访问该元素的线程。
在设计线程安全的过程中,需要包含以下三个基本要素
找出构成对象状态的所有变量
找出约束状态变量的不变性条件
建立对象状态的并发访问管理策略
可以通过封闭机制与合适的加锁策略结合起来,可以确保以线程安全的方式来使用非线程安全的对象
迭代访问共享容器:可能会报异常:ConcurrentModificationException
所有对共享容器进行迭代的地方度需要加锁。容器的hashCode和equals访问也会间接地执行迭代操作,同样当containsAll,removeAll和retainAll等方法,以及把容器作为参数的构造函数,都会对容器进行迭代。所有这些间接地迭代操作都可能抛出ConcurrentModificationException。
在构建高可靠地程序是,有界队列是一种强大的资源管理工具:它们能抑制并防止产生过多的工作项,使应用程序在符合过载的情况下变得更加健壮。