java.util.concurrent,并发编程常用的工具类:包含了线程池、阻塞队列、计时器、同步器、并发集合等 作者:Dong Lea。
Lock
Lock 本质上是一个接口,它定义了释放锁和获得锁的抽象方法,定义成接口就意
味着它定义了锁的一个标准规范,也同时意味着锁的不同实现。
Lock 有很多的锁的实现,但是直观的实现是 ReentrantLock 重入锁。
1.ReentrantLock:
表示重入锁,表示支持重新进入的锁,它是唯一一个实现了 Lock 接口的类。重入锁指的是线程在获得锁之后,再次获取该锁不需要阻塞,而是直接关联一次计数器增加重入次数。
重入锁的设计目的是避免线程的死锁。
形成死锁的原因:
调用 demo 方法获得了当前的对象锁,然后在这个方法中再去调用demo2,demo2 中的存在同一个实例锁,这个时候当前线程会因为无法获得demo2 的对象锁而阻塞,就会产生死锁。
案例:
public class ReentrantDemo{
public synchronized void demo(){
System.out.println("begin:demo");
demo2();
}
public void demo2(){
System.out.println("begin:demo1");
synchronized (this){
}
}
public static void main(String[] args) {
ReentrantDemo rd=new ReentrantDemo();
new Thread(rd::demo).start();
}
}
ReentrantLock的使用案例:
public class AtomicDemo {
private static int count=0;
static Lock lock=new ReentrantLock();
public static void inc(){
lock.lock();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
lock.unlock();
}
public static void main(String[] args) throws
InterruptedException {
for(int i=0;i<1000;i++){
new Thread(()->{AtomicDemo.inc();}).start();;
}
Thread.sleep(3000);
System.out.println("result:"+count);
}
}
ReentrantReadWriteLock
我们以前理解的锁,基本都是排他锁,也就是这些锁在同一时刻只允许一个线程进
行访问,而读写锁在同一时刻可以允许多个读线程访问,但是在写线程访问时,所有的读线程和其他写线程都会被阻塞。也就是说只维护读锁和写锁。
读写锁的性能都会比排它锁好,因为大多数场景读是多于写的。在读多于写的情况下,读写锁能够提供比排它锁更好的并发性和吞吐量。
**读写锁案例**
public class LockDemo {
static Map<String,Object> cacheMap=new HashMap<>();
static ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
static Lock read=rwl.readLock();
static Lock write=rwl.writeLock();
public static final Object get(String key) {
System.out.println("开始读取数据");
read.lock(); //读锁
try {
return cacheMap.get(key);
}finally {
read.unlock();
}
}
public static final Object put(String key,Object value){
write.lock();
System.out.println("开始写数据");
try{
return cacheMap.put(key,value);
}finally {
write.unlock();
}
}
}