锁的使用

锁用于解决多线程对共享资源的同时访问,而引起的非线程安全问题:某一时该只有一条线程可以访问共享资源,达到了线程安全的目的,但同时也限制了并发处理的速度。

 

锁的分类:

同步锁: synchronized 是java 内置的语法

可重入锁:ReentrantLock  是一个java类

读写锁:ReentrantReadWriteLock 是一个java类

 

 

锁定的范围:

 由于锁使线程互斥访问,未获得锁的线程会阻塞,限制了并发处理的速度,因此线程应该锁定尽量小的范围及尽快的释放锁。

 

 比如一家企业,有10个厕所,每个厕所有5个坑,每个员工都要上厕所,厕所的同一个坑不可能由多人共同使用,每个员工相当于一线线程,茅坑相当于共享资源,因此需要多个员工之间互斥使用同一个茅坑。

 

 错误的锁定范围:

    10个厕所:意味着 某个员工使用某个茅坑时,所有厕所都不能使用,严重浪费资源,影响并发使用率。 

    每个厕所:意味着 某个员工使用某个茅坑时,该厕所不能被别人使用,其他9个厕所允许9个人分别使用,浪费资源,影响并发使用率。

    

 正确的锁定范围:   

    每个茅坑:意味着 某个员工使用某个茅坑时,该茅坑不能被别人使用,其他49个茅坑允许49个人分别使用。

    

java中的锁定对象:

synchronized的锁定对象:

  语法:synchronized(被锁定对象)  或 在方法签名上声明

  全局锁定:Class对象,static 对象及方法,singleton 实例,equals相等的String对象

  部分锁定:某个多例类的实例,不同实例由不同的线程同时访问。

  

public class Test {
 
   public synchronized  void kk(){//做用于方法,锁定当前实例,不同实例间不影响
 
  }
  public static synchronized void ww(){//做用于静态方法锁定的是Class对象
 
  }
  public void t(Object obj){
    synchronized(obj){//锁定指定对象
     //
    }
  }
  public void f( ){
     synchronized(this){//锁定当前实例
     //
  }
 }
}

 

 

 

 

  

ReentrantLock 锁定对象:

同一个ReentrantLock实例,不同实例可由不同线程同时访问。

  用法:

  

class X {
   private final ReentrantLock lock = new ReentrantLock();
   public void m() { 
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

 

 

 

  

ReentrantReadWriteLock          

readLock  共享锁,占用锁时,同一个ReentrantReadWriteLock实例的writeLock,被阻塞,同一个ReentrantReadWriteLock实例的readLock可以同时访问。

writeLock 独占锁,占用锁时,同一个ReentrantReadWriteLock实例的writeLock和readLock阻塞,直至锁被释放,不同实例可由不同线程同时访问

 

 

                                 

      

  

锁的释放: 

  1 代码执行完成,退出锁定

  2.由于条件不足,而无法继续执行,主动释锁定,等待条件满足,当条件满足时,需要另一条线程唤醒等待线程,唤醒的线程争得锁之后主动释放锁的代码之后执行

 

 A.synchronized

 1.synchronized方法或代码块执行完成,而释放锁

   2.synchronized:被锁定对象.wait()方法被调用时释放锁而等待,  被唤醒方式:被锁定对象.notifyAll()(这两个方法需要执行锁时才能执行)

  B. ReentrantLock

    1.代码执行完成后,ReentrantLock.unlock()代码被调用,而释放锁

    2.由ReentrantLock.newCondition()生成Condition对象的await()方法被调用时,释放锁而等待,被唤醒方式同一个Condition对象的signalAll方法被调用。(这两个方法需要执行锁时才能执行)

  C.ReentrantReadWriteLock

    1.代码执行完成后,ReentrantReadWriteLock的readLock 或writeLock 对象的unlock方法被调用,而释放锁

    2.readLock 不支持由条件不足释放锁定而等待条件满足。writeLock.newCondition()生成Condition对象的await()方法被调用时,释放锁而等待,被唤醒方式同一个Condition对象的signalAll方法被调用。(这两个方法需要执行锁时才能执行)

    

class RWDictionary {
    private final Map<String, Data> m = new TreeMap<String, Data>();
    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    private final Lock r = rwl.readLock();
    private final Lock w = rwl.writeLock();
 
    public Data get(String key) {
        r.lock();
        try { return m.get(key); }
        finally { r.unlock(); }
    }
    public String[] allKeys() {
        r.lock();
        try { return m.keySet().toArray(); }
        finally { r.unlock(); }
    }
    public Data put(String key, Data value) {
        w.lock();
        try { return m.put(key, value); }
        finally { w.unlock(); }
    }
    public void clear() {
        w.lock();
        try { m.clear(); }
        finally { w.unlock(); }
    }

 

 

信号量Semaphore :

 

一般用于限制对某些资源固定数量的访问。 

Semaphore维护了N个的许可,某线程通过acquire()获取一个许可或acquire(int permits) 获取多许可,如果许可数量N大于线程要求的许可数,线程得到许可并可以继续执行。

否则线程阻塞,等待某线程释放许可。

某线程释放许可,许可数量增加并唤醒被阻塞的线程,阻塞线程唤醒后再试着获取许可,获取成功则继续执行否则再次阻塞。

 

    

不使用锁解决非线程安全问题(有一定局限性):

  实现方式:一般使用CAS (compare and swap)  实现

  使用场景:AtomicLongFieldUpdater  对volatile long 字段进行原子更新

            AtomicReferenceFieldUpdater 对 volatile 字段进行原子更新   

            AtomicReference 原子方式更新的对象引用

      

  示例:ConcurrentLinkedQueue

   

boolean casNext(Node<E> cmp, Node<E> val) {
            return nextUpdater.compareAndSet(this, cmp, val);
    }
    
     public boolean offer(E e) {
        if (e == null) throw new NullPointerException();
        Node<E> n = new Node<E>(e, null);
        for (;;) {
            Node<E> t = tail;
            Node<E> s = t.getNext();
            if (t == tail) {
                if (s == null) {
                    if (t.casNext(s, n)) {
                        casTail(t, n);
                        return true;
                    }
                } else {
                    casTail(t, s);
                }
            }
        }
    }
    
     private static final
            AtomicReferenceFieldUpdater<Node, Node>
            nextUpdater =
            AtomicReferenceFieldUpdater.newUpdater
            (Node.class, Node.class, "next");

 

            

 

 

  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值