设计一个线程安全的程序尤为重要,尤其是在高并发环境下。
对一些的概念进行记录,如果不对的地方还望指正。
概念
-
volatile 线程在每次使用变量的时候,都会读取变量修改后的最的值, 但volatile只能保证可见性,无法保证原子性,所以不能用来做原子性操作。
-
synchronized Synchronized关键字经过编译后,会在同步块的前后分别形成monitorenter和monitorexit这两个字节码指令,这两个字节码都需要一个reference类型的参数来指明要锁定和解锁的对象。虽然synchronized可以保证在同一时刻,只有同一个线程可以访问某一方法或者代码块,但是锁机制每次阻塞或唤醒一个线程的时候,都需要操作系统来完成,这里就涉及到系统状态转换的问题(从用户态转换到核心态),这个过程会耗费CPU很多的时间,成本较大。所以要合理把握锁的粒度。
-
CountDownLatch 能够使一个线程等待其他线程完成各自的工作后再执行。他是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
*********************************************************************************************************************
线程安全
线程安全实现的方法主要有:非阻塞同步(CAS)、互斥同步、线程局部变量(threadLocal)、wait和notify、java.util.concurrent并发工具包、volatile保证变量的线程安全等。
-
CAS:CompareAndSwap,一种保证操作原子性的方法,主要流程是取得i的值(A),进行计算得到(B),去内存中取的值(V),只有A=V 时,才会进行B=A的操作,否则重新取A,直到赋值成功(循环太多次,对性能有影响)。但这种方法会有一个问题---ABA,即在取A和取V的间隙,对象发生过改变,java在处理该问题时,提供了一个带有标记的原子引用类“AtomicStampedReference”,它可以通过控制变量值的版本来保证CAS的正确性。如果要处理ABA问题,互斥同步比原子类更高效。
-
互斥同步 一般使用synchronized关键字实现互斥同步
-
线程局部变量 每个线程的Thread对象中都有一个ThreadLocalMap对象,这个map存储了一组以该线程所对应的哈希码ThreadLocal.threadLocalHashCode为键。可以理解为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
网友评论