zoukankan      html  css  js  c++  java
  • 第二部分:并发工具类14->Lock和condition(上)

    1.并发领域核心问题互斥

    同一时刻只能一个线程访问共享资源。
    Lock解决互斥问题

    2.并发领取核心问题同步

    线程之间如何通信,协作
    Condition解决同步问题

    3.为什么要重复造轮子

    synchronized已经实现管程,为什么要再实现一遍管程

    synchronized性能不好
    synchronized在死锁方面,无法破坏不可抢占条件,synchronized申请不到,线程直接阻塞状态了,就是线程的BLOCK状态,线程没有cpu执行权限,而且也不会释放占用的资源

    4.重复造的轮子优势是啥

    1.响应中断。可以接受中断信号,唤醒线程,就会释放锁,破坏了不可抢占条件。(自己获取的锁,别人抢不到)
    2.支持超时。在一段时间内没有获取锁,不进入阻塞状态,而是返回错误,线程也会释放持有的锁,可以破坏不可抢占条件。
    3.非阻塞获取锁。获取锁失败,不进入阻塞状态,而直接返回。这个线程有机会会释放曾经的锁

    就可以弥补synchronized问题。

    对应到Lock接口上的三个方法

    
    // 支持中断的API
    void lockInterruptibly() 
      throws InterruptedException;
    // 支持超时的API
    boolean tryLock(long time, TimeUnit unit) 
      throws InterruptedException;
    // 支持非阻塞获取锁的API
    boolean tryLock();
    

    5.Lock如何保证可见性

    synchronized中的可见性,是因为happens-before规则,
    synchronized的解锁happens-before的加锁操作

    那么Lock呢?

    
    class X {
      private final Lock rtl =
      new ReentrantLock();
      int value;
      public void addOne() {
        // 获取锁
        rtl.lock();  
        try {
          value+=1;
        } finally {
          // 保证锁能释放
          rtl.unlock();
        }
      }
    }
    

    利用了volatile相关的happens-before规则,
    ReentrantLock里内嵌了一个volatile的成员变量state,获取锁的时候回读写state的值,解锁的时候也会读写state值。

    
    class SampleLock {
      volatile int state;
      // 加锁
      lock() {
        // 省略代码无数
        state = 1;
      }
      // 解锁
      unlock() {
        // 省略代码无数
        state = 0;
      }
    }
    

    1.顺序性原则,线程T1,value += 1 Happens-before 释放锁的操作unlock()
    2.volatile变量规则,由于state = 1会先读取state,所以线程T1的unlock()操作happens-before与线程T2的lock()操作
    3.传递性原则,先T1的value += 1 Happens-before 与T2的lock()操作

    6.可重入锁

    线程可重复获取同一把锁

    
    class X {
      private final Lock rtl =
      new ReentrantLock();
      int value;
      public int get() {
        // 获取锁
        rtl.lock();         ②
        try {
          return value;
        } finally {
          // 保证锁能释放
          rtl.unlock();
        }
      }
      public void addOne() {
        // 获取锁
        rtl.lock();  
        try {
          value = 1 + get(); ①
        } finally {
          // 保证锁能释放
          rtl.unlock();
        }
      }
    }
    

    线程T1执行到(1)处,已经获取到锁rtl,在(1)调用get方法,会在(2)再次对rtl进行加锁操作,可以再次加锁成功,非重入锁,那么线程T1就会被阻塞。

    7.公平锁与非公平锁

    ReentrantLock,两个构造函数,一个无参,一个传fair参数的构造函数
    fair参数代表的是锁的公平策略
    true就是公平锁,false就是非公平锁

    公平与不公平,看的是,锁释放的时候的策略
    公平锁,锁释锁,从等待队列中唤醒一个等待的线程,谁等待的时间长,就唤醒谁
    非公平锁,释放锁的时候,不提供这个公平保证,可能等待的时间短的反而先被唤醒.

    8.用锁的最佳实践

    1.永远只在更新对象的成员变量时加锁
    2.永远只在访问可变的成员变量时加锁
    3.永远不再调用其他对象的方法时加锁

    原创:做时间的朋友
  • 相关阅读:
    Oracle适配问题解决
    Oracle12C创建视图权限不足
    Oracle12C配置对外访问
    Oracle12C创建scott账户
    Oracle12C安装配置文档
    Redis适配采坑记
    Redis安装问题解决方案
    Redis Linux 安装部署
    【计网 第四章-2】
    【信息论编码2】测度论
  • 原文地址:https://www.cnblogs.com/PythonOrg/p/14959301.html
Copyright © 2011-2022 走看看