java ReentranLock锁

一、效果和synchronized同样,均可以同步执行,lock方法得到锁,unlock方法释放锁java

使用示例:ide

package com.test;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {
    
    private Lock lock = new ReentrantLock();
    public void methodA() {
        try {
            lock.lock();
            System.out.println("methodA begin ThreadName = " + Thread.currentThread().getName() + "time=" + System.currentTimeMillis());
            Thread.sleep(3000);
            System.out.println("methodA end ThreadName = " + Thread.currentThread().getName() + "time=" + System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    
    public void methodB() {
        try {
            lock.lock();
            System.out.println("methodB begin ThreadName = " + Thread.currentThread().getName() + "time=" + System.currentTimeMillis());
            Thread.sleep(3000);
            System.out.println("methodB end ThreadName = " + Thread.currentThread().getName() + "time=" + System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
package com.test;

public class Run {
    
    public static void main(String[] args) {
        
        MyService myService = new MyService();
        Thread t1 = new Thread(new Runnable() {
            
            @Override
            public void run() {
                myService.methodA();
            }
        });
        Thread t2 = new Thread(new Runnable() {
            
            @Override
            public void run() {
                myService.methodB();
            }
        });
        t1.start();
        t2.start();
    }
}
结果:
methodA begin ThreadName = Thread-0time=1527821296840
methodA end ThreadName = Thread-0time=1527821299841
methodB begin ThreadName = Thread-1time=1527821299841
methodB end ThreadName = Thread-1time=1527821302841

注意:必需要在finally块里调用lock.unlock() 释放锁.spa

二、使用Condition实现等待/通知:线程

  awati() 与 signal() 方法:code

  

package com.test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {
    
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    
    public void testWait() {
        try {
            lock.lock();
            System.out.println("wait");
            condition.await();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    
    public void testSignal() {
        try {
            lock.lock();
            condition.signal();
        } finally {
            lock.unlock();
        }
    }
    
}
  • 经过Condition对象来使线程wait,必须先执行lock.lock()得到锁。
  • Condition对象的signal()方法能够唤醒线程.
  • Condition的awati()方法和Object 中的wati()方法等效.
  • Condition的signal()方法和Object 中的notify()方法等效.
  • Condition的signalAll()方法和Object中的notifyAll()方法等效。

三、公平锁和非公平锁:对象

  公平锁标识线程获取锁的顺序是按照线程加锁的顺序来分配的。即先来先得的FIFO先进先出顺序。而非公平锁就是一种获取锁的抢占机制,是随机得到锁的。blog

  

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

四、ReentrantLock 类的方法:get

  • int getHoldCount() 的做用是查询当前线程保持此锁定的个数,也就是调用lock()方法的次数。
  • int getQueueLength()的所用是返回正在等待获取此锁的线程估计数 。好比有5个线程,1个线程首先执行await()方法,那么调用此方法的返回值是4.
  • int getWaitQueueLength(Condition condition)的所用是返回等待与此锁定相关的给定条件Condition的线程估计数,好比5个线程都执行了Condition的await()方法 ,那么返回值就是5.
  • boolean hasQueuedThreads()的做用是查询是否有线程正在等待获取此锁.
  • boolean hasWaiters(Condition condition)的做用是查询是否有线程正在等待与此锁定有关的condition条件。
  • boolean isFair()的做用是判断是否是公平锁.
  • boolean isHeldByCurrentThread()的做用是查询当前线程是否保持此锁。
  • boolean isLocked()的做用是查询此锁是否由任意线程保持。
  • void lockInterruptibly()的做用是:若是当前线程未被中断,则获取锁定,若是已经被中断则出现异常。
  • boolean tryLock()的做用是仅在调用时锁定未被另外一个线程保持的状况下,才获取该锁定。
  • boolean tryLock(long timeout, TimeUnit unit) 的做用是,若是锁定在给定等待时间内没有被领一个线程保持,且当前线程未被中断,则获取该锁定。

五、ReentrantReadWriteLock 类,读写锁:同步

  类ReentrantLock 具备彻底互斥排他的效果,即同一时间只有一个线程在执行lock()方法后面的任务。it

  读写锁表示也有两个锁,一个是读操做相关的锁,也成为共享锁;另外一个是写操做相关的锁,也就排它锁。也就是多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。在没有线程进行写操做时,进行读取操做的多个线程均可以获取读锁,而进行写入操做的线程只有在获取写锁后才能进行写入操做。即多个线程能够同时进行读操做,但同一时刻只有一个线程能够进行写操做。

  • 读读共享

  

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void read() {
        try {
            try {
                lock.readLock().lock();
                System.out.println("获取读锁:" + System.currentTimeMillis());
                Thread.sleep(1000);
            } finally {
                lock.readLock().unlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  • 写写互斥

  

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void write() {
        try {
            try {
                lock.writeLock().lock();
                System.out.println("获取写锁:" + System.currentTimeMillis());
                Thread.sleep(1000);
            } finally {
                lock.writeLock().unlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  • 读写互斥

  

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void read() {
        try {
            try {
                lock.writeLock().lock();
                System.out.println("获取读锁:" + System.currentTimeMillis());
                Thread.sleep(1000);
            } finally {
                lock.writeLock().unlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public void write() {
        try {
            try {
                lock.writeLock().lock();
                System.out.println("获取写锁:" + System.currentTimeMillis());
                Thread.sleep(1000);
            } finally {
                lock.writeLock().unlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 lock 与 lockInterruptibly比较区别在于:
 lock 优先考虑获取锁,待获取锁成功后,才响应中断。
 lockInterruptibly 优先考虑响应中断,而不是响应锁的普通获取或重入获取

synchronized 和 lock 的用法区别:

  1. synchronized 是托管给JVM执行的。而Lock是Java写的控制锁的代码。
  2. synchronized 原始采用的是CPU悲观锁机制,即线程得到的是独占锁。独占锁意味着其余线程只能依靠阻塞来等待线程释放锁。而在CPU转换线程阻塞时会引发线程上下文切换,会致使效率很低。
  3. Lock用的是乐观锁方式。每次不加锁而是假设没有冲突而去完成某项操做,若是由于冲突失败就重试。直到成功为止。
  4. ReentrantLock必须在finally中释放锁,而synchronized不须要。
  5. ReentrantLock提供了可轮询的锁请求,他能够尝试的去取得锁,若是取得成功则继续处理,取得不成功,能够等下次运行的时候处理,因此不容易产生死锁。而synchronized则一旦进入锁请求要么成功,要么一直阻塞,因此更容易产生死锁。
  6. synchronized的话,锁的范围是整个方法或synchronized块部分;而Lock由于是方法调用,能够跨方法,灵活性更大。

使用ReentrantLock的场景:

  1. 某个线程在等待一个锁的控制权的这段时间须要中断。
  2. 须要分开处理一些wait-notify,ReentrantLock里面的Condition应用,可以控制notify哪一个线程.
  3. 具备公平锁功能,每一个到来的线程都将排队等候.
相关文章
相关标签/搜索