java多线程之锁


    • 锁的分类
      • 偏向锁
      • 轻量级锁
      • 死锁
        • 场景
          • 两个线程分别占有另一线程需要的资源,等待对方互相释放锁,或是某一线程释放是发生异常没释放掉,导致系统不可用的一个现象。
        • 分析
          • jps 查看java进程的pid
          • jstack pid dump哪个线程出现了问题
        • 避免死锁的方法
          • 避免一个线程同时获取多个锁
          • 避免一个线程在锁内同时占有多个资源,经理保证每个锁只使用一个资源
          • 尝试使用定时锁,如 lock.tryLock(timeOut)来替代使用内部锁
          • 对于数据库锁,加锁与解锁必须在同一个connection连接内,否则会出现解锁失败的情况
        • synchronized的使用与原理
          • 大致介绍一下它属于java并发编程中常见的一个锁,属于重量级锁。
          • 使用
            • 加在普通方法上 锁为当前的实例对象
            • 加在静态方法上,锁为当前类的class对象
            • 同步方法块上,锁时括号内配置的对象
          • 原理
            • 当一个线程试图操作同步代码块时,必须先获取锁,同时在退出或抛出异常时必须释放锁。从jvm层次来看,使用Monitor对象来控制同步方法,这里会出现moniterenter(开始)和monitorexit(结束)指令。线程执行到开始指令会尝试回去moniter所有权即获取对象的锁。
        • Lock
          • 手动加锁与释放
Lock lock = new ReentrantLock();//放在try外面
lock.lock();
try {

    }finally {

     } 
  • 与synchronized不同
    • 尝试非阻塞性的获取
    • 超时获取
    • 被中断的获取
      • 常见方法
        • void lock() 
          void lockInterruptibly() 可中断
          Condition newCondition();
          boolean tryLock(); 尝试获取
          boolean tryLock(long time, TimeUnit unit);
          void unlock(); 释放锁
      • 自定义同步组件
        • 静态内部类Sync extends AbstractQueuedSynchronizer
        • implements Lock
        • lock –> sync.xxx()
        • 线程获取锁失败后会放入同步队列中等待
      • 分析同步器是如何完成线程同步的
        • 同步队列
          • 节点
          • 前驱 后置引用
          • FIFO
          • 设置首节点
          • 设置尾节点
          • 独占式同步状态获取与释放
          • 简单说,在获取同步状态时,同步器维护了一个队列,获取失败的线程会进入队列并在队列中自旋,移出队列或停止自旋的条件时前驱节点为头节点,且成功获取了同步状态,释放同步状态时需要调用方法释放状态,唤醒头节点的后置节点。
            • 共享式同步状态获取与释放
              • 在同一个时刻能有多个线程获取到同步状态
              • tryAquiredShared()
              • tryReleaseShared()
            • 独占式超时获取同步状态
              • 会有一个等待时间,在指定时间内没获取到会从等待的逻辑中返回
            • 自定义同步器
        • 重入锁
          • 支持一个线程对资源重复加锁
          • synchronized 支持隐式重入
          • 公平与否
            • 在绝对时间上,先对锁进行获取的请求一定先满足那么就是公平的 先到先得FIFO
          • 实现
            • 指的是任意线程在获取锁之后重新获取该锁而不会被阻塞
              • 线程再次获取锁
              • 锁的最终释放 计数器 ++ –
          • 公平锁保证了FIFO其代价是进行了大量的线程切换
          • 非公平锁虽然可能会造成线程饥饿但是极少切换线程
        • 读写锁
          • 在同一时刻允许多个线程读,但是写线程访问时其他线程均被阻塞
          • ReentrantReadWriteLock
          • 实例代码 通过读写锁保证了线程安全
          • public class Cache { 
            static Map

你可能感兴趣的:(并发编程)