您的位置:首页 > 编程语言 > Java开发

java线程安全的实现方法_笔记

2018-03-16 22:00 323 查看
阅读《深入理解java虚拟机》后的阅读笔记。
1、 互斥同步
同步时指在多个线程并发访问共享数据时,保证共享数据在同一个时刻只被一个(或者是一些,使用信号量的时候)线程使用。而互斥是实现同步的一种手段,临界区,互斥量和信号量都是主要的互斥实现方式。
  1.1 在java中最基本的互斥同步手段就是synchronized关键字,synchronized关键字经过编译之后,会在同步块的前后分别形成monitorenter和monitorexit这两个字节码指令。根据虚拟机规范要求,在执行monitorenter指令时,首先要尝试获取对象的锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象的锁,把锁的计数加1,相应的,在执行monitorexit指令时会将锁计数器减1,当计数器为0时,锁就被释放。如果获取对象锁失败,那当前线程就要阻塞等待,直到对象锁被另外一个线程释放为止。
注意:
因为java的线程是映射到操作系统的原生线程之上的,如果要阻塞或唤醒一个线程,都需要操作系统来帮忙完成,这就需要从用户态转换到核心态中,因此状态转换需要耗费很多的处理器时间。多以synchronized是java语言中一个重量级(Heavyweight)的操作。
  1.2 使用java.util.concurrent包中的重入锁(ReentrantLock)来实现同步。相比synchronized,ReentrantLock增加了一些高级功能,主要有以下三项:
     等待可中断:当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情
     可实现公平锁:多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁
     锁可以绑定多个条件:一个ReentrantLock对象可以同时绑定多个Condition对象
2、 非阻塞同步
互斥同步最主要的问题就是进行线程阻塞和唤醒所带来的性能问题,这是一种悲观的并发策略。总是认为只要不去做正确的同步措施(加锁),那就肯定会出问题,无论共享数据是否真的会出现竞争,它都要进行加锁、用户态核心态转换、维护锁计数器和检查是否有被阻塞的线程需要被唤醒等操作。
随着硬件指令集的发展,我们可以使用基于冲突检测的乐观并发策略。先进行操作,如果没有其他线程征用数据,那操作就成功了;如果共享数据有征用,产生了冲突,那就再进行其他的补偿措施。这种乐观的并发策略的许多实现不需要线程挂起,所以被称为非阻塞同步。
3、无同步方案
  3.1 可重入代码:这种代码也叫做纯代码(Pure Code),可以在代码执行的任何时刻中断他,转而去执行另外一段代码(包括递归调用它本身),它可以保证原来的程序不会出现任何错误。
  3.2 线程本地存储:如果一段代码中所需要的数据必须与其他代码共享,那就看看这些共享数据的代码是否能保证在同一个线程中执行?如果能保证,我们就可以把共享数据的课件范围限制在同一个线程之内,这样,无须同步也能保证线程之间不出现数据争用问题。(例如:“生产者-消费者”模式,都会将产品的消费过程尽量在一个线程中消费完)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java多线程