欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java多线程-Lock

程序员文章站 2024-01-08 08:30:28
...

ReentrantLock

ReentrantLock可以和synchronized达到一样的效果,并且扩展功能上也更加强大,而且使用更加灵活。

       Lock lock=new ReentrantLock();
       //加锁
       lock.lock();
       //取消锁
       lock.unlock();

等待通知模式:
synchronized与wait()和notify方法结合可以实现等待通知模式

wait():释放占有的对象锁,线程进入等待池,释放cpu,而其他正在等待的线程即可抢占此锁,获得锁的线程即可运行程序。而sleep()不同的是,线程调用此方法后,会休眠一段时间,休眠期间,会暂时释放cpu,但并不释放对象锁。也就是说,在休眠期间,其他线程依然无法进入此代码内部。休眠结束,线程重新获得cpu,执行代码。wait()和sleep()最大的不同在于wait()会释放对象锁,而sleep()不会!

notify(): 该方法会唤醒因为调用对象的wait()而等待的线程,其实就是对对象锁的唤醒,从而使得wait()的线程可以有机会获取对象锁。调用notify()后,并不会立即释放锁,而是继续执行当前代码,直到synchronized中的代码全部执行完毕,才会释放对象锁。JVM则会在等待的线程中调度一个线程去获得对象锁,执行代码

1个线程访问A的代码,拿到obj的锁,但是执行了obj.wait()马上就释放了obj的锁
这时候另一个拿到obj锁进入B的代码,但是执行了obj.notify(),通知等待的线程准备启动


   //A
      synchronized (obj){
            obj.wait();
        }

        //B
        synchronized (obj){
            obj.notify();
        }

ReentrantLock可可以实现同样的功能。而且更加灵活,可以实现选择性通知。

Lock lock=new ReentrantLock();
Condition condition = lock.newCondition();

  try {
            lock.lock();
            System.out.println("A");
            //等待
            condition.await();
            System.out.println("B");
   } catch (InterruptedException e) {
            e.printStackTrace();
   }finally {
            lock.unlock();
   }

  // 释放
  // condition.signal();

执行结果为:显示A,然后线程处于WAITING状态
注意: condition.await();必须在lock()范围内,不然会报异常。

Object类的wait(),相当于Condition的await();
Object类的wait(long timeout),相当于Condition的await(long time,TimeUnit unit);
Object类的notify(),相当于Condition的signal();
Object类的notifyAll(),相当于Condition的signalAll();

多个Condition
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();

conditionA 只能唤醒conditionA 的await(),也就是每个Condition 都是单独隔离的

公平锁,非公平锁:
公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的(lock.lock()顺序),即先来的先得到。
非公平锁是一个锁的抢占机制,是随机获取锁,可能造成某些线程一直拿不到锁。

//公平锁
Lock lock=new ReentrantLock(true);
//非公平锁
Lock lock=new ReentrantLock(false);
//默认非公平锁
Lock lock=new ReentrantLock();

方法

    //查询当前线程保持锁定的个数,就是调用lock()方法次数
    lock.getHoldCount();

    //返回正等待获取此锁定的线程估计数
    lock.getQueueLength();

    //返回等待与此锁定相关的给定条件Condition的线程估计数
    lock.getWaitQueueLength(condition);

    //查询指定的线程是否正在等待此锁
    lock.hasQueuedThread(thread);

    //查询是否有线程正在等等此锁
    lock.hasQueuedThreads();

    //查询是否有线程正在等待此锁定有关的condition条件
    lock.hasWaiters(condition);

    //是否是公平锁
    lock.isFair();

    //查询当前线程是否保持锁
    lock.isHeldByCurrentThread();

    //查询此锁是否由任意的线程保持
    lock.isLocked();

    //如果当前线程未被中断,则获取锁定,如果已经被中断则出现异常
    lock.lockInterruptibly();

    //仅在调用时锁未被其他线程锁定的情况下,才获取该锁。
    lock.tryLock();

    //锁定在给等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。
    lock.tryLock(long timeout,TimeUnit unit);

ReentrantReadWriteLock

ReentrantLock具有完全互斥的效果,同一个时间只有一个线程在执行lock()方法后面的内容,保证了实例变量的线程安全性。但是效率比较低下。

ReentrantReadWriteLock读写锁,有两个锁。一个是读操作相关的锁,也叫做共享锁;另一个是写操作的相关的锁,也叫做排他锁。(1)也就是多个读锁间不互斥;(2)读锁写锁互斥;(3)写锁写锁互斥。
在没有线程Thread进入写入操作时,进行读取操作的多个Thread都可以读取读锁,而进入写入操作的Thread只有在获取写锁后才能进行写入操作。即多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作

  ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
  lock.readLock().lock();

  lock.writeLock().lock();

过程:
“读写”、“写读”、“写写”,互斥
当一个线程已经获得了读锁,而且还没释放正在运行,这时候有一个线程要获取写锁,则等待。
当一个线程已经获得了写锁,而且还没释放正在运行,这时候有一个线程要获取读锁,则等待。
当一个线程已经获得了写锁,而且还没释放正在运行,这时候有一个线程要获取写锁,则等待。

“读读”,不互斥
当多个线程都想要获得一个读锁时,发现没有其他线程拥有写锁,则运行

上一篇:

下一篇: