Lock对象的使用

1. ReentrantLock

  • 使用ReentrantLock可以实现同步
  • 使用ReentrantLock结合Condition类可以实现“选择性通知”,这个功能是Condition类默认提供的。Condition对象的作用是控制并处理线程的状态,它可以使线程呈wait状态,也可以让线程继续运行;
  • 默认情况下,ReentrantLock类使用的是非公平锁。

  Condition对象的await()方法:作用是使当前线程在接到通知或被中断之前一直处于等待wait状态,它和wait()方法的作用是一样的。其次,必须在condition.await()方法调用之前使用lock.lock()代码获得锁。

  • Object类中的wait()方法相当于Condition类中的await()方法。
  • Object类中的wait(long timeout)方法相当于Condition类中的await(long time,TimeUnit unit)方法。
  • Object类中的notify()方法相当于Condition类中的signal()方法。
  • Object类中的notifyAll()方法相当于Condition类中的signalAll()方法。

2. 公平锁与非公平锁

  公平锁:采用先到先得的策略每次获取锁之前都会检查队列里面有没有排队等待的线程,没有才会尝试获取锁,如果有就将当前线程追加到队列中

  非公平锁:采用“有机会插队”的策略,一个线程获取锁之前要先去尝试获取锁而不是在队列中等待,如果获取锁成功,则说明线程虽然是后启动的,但先获得了锁,这就是“作弊插                              队” 的效果。如果获取锁没有成功,那么才将自身追加到队列中进行等待

public class Service {
    public Lock lock;
    public Service(boolean fair){
        lock = new ReentrantLock(fair);
    }
    public void testMethod(){
        try {
            lock.lock();
            System.out.println("testMethod" + Thread.currentThread().getName());
            Thread.sleep(500);
            lock.unlock();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class MyThread extends Thread{
    private Service service;
    public MyThread(Service service){
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.testMethod();
    }
}
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Service service = new Service(false);
        MyThread[] thread1 = new MyThread[5];
        MyThread[] thread2 = new MyThread[5];
        for (int i = 0; i < 5; i++) {
            thread1[i] = new MyThread(service);
            thread1[i].setName("thread1+++" + (i + 1));
        }
        for (int i = 0; i < 5; i++) {
            thread2[i] = new MyThread(service);
            thread2[i].setName("thread2---" + (i + 1));
        }
        for (int i = 0; i < 5; i++) {
            thread1[i].start();
        }
        Thread.sleep(500);
        for (int i = 0; i < 5; i++) {
            thread2[i].start();
        }
    }
}
//输出结果如下
testMethodthread1+++1
testMethodthread2---1
testMethodthread1+++2
testMethodthread1+++3
testMethodthread1+++4
testMethodthread1+++5
testMethodthread2---5
testMethodthread2---3
testMethodthread2---4
testMethodthread2---2
//显然后启动的进程先抢到了锁,说明这是非公平锁

//修改为公平锁
Service service = new Service(true);
//运行结果如下:
testMethodthread1+++1
testMethodthread1+++2
testMethodthread1+++3
testMethodthread1+++4
testMethodthread1+++5
testMethodthread2---1
testMethodthread2---2
testMethodthread2---3
testMethodthread2---4
testMethodthread2---5
//很显然,无任何抢占,都是按照顺序执行,这就是公平锁的特点

3. ReentrantReadWriteLock

  ReentrantLock类具有完全互斥排他的效果,同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务,这样虽然能够保证线程的安全,但是效率非常低下。

  ReentrantReadWriteLock—读写锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也称排他锁。读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。可以提高程序的运行效率。

posted @ 2021-08-09 23:33  明羽1  阅读(74)  评论(0)    收藏  举报